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.
 
 
 
 
 
 

339 lines
17 KiB

using Google.Protobuf.WellKnownTypes;
using LitJson;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Asn1.Ocsp;
using ProtoCSStruct;
using SimpleHttpServer;
using Sog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace HttpProxyPay
{
public static class WXHandler
{
private static ConcurrentDictionary<string, JsonData> order_cache = new ConcurrentDictionary<string, JsonData>();
private static string accessToken = null;
private static long expireTimeSec = 0;
private static string jstiket = null;
private static long tiketExpire = 0;
public static void CheckFreshAccessToken(bool force = false)
{
long now = HttpProxyPayServerUtils.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"] = HttpProxyPayServerUtils.GetServerConfig().wxAppId;
j["secret"] = HttpProxyPayServerUtils.GetServerConfig().wxSec;
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("WXHandler.checkFreshAccessToken, get ret:{0}", ret);
if (ret == null)
{
return;
}
LitJson.JsonData jsonData = JsonMapper.ToObject(ret);
accessToken = jsonData["access_token"].ToString();
expireTimeSec = now + ((long)jsonData["expires_in"]);
}
}
public static void MiniJSAPICall(HttpContext httpCtx)
{
TraceLog.Trace("WXHandler.MiniJSAPICall 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);
postParams.TryGetValue("callback", out var jsoncallback);
postParams.TryGetValue("orderId", out var orderId);
postParams.TryGetValue("url", out var url);
postParams.TryGetValue("uid", out var uid);
url += "?uid="+uid+"&orderId=" + orderId;
if(order_cache.TryGetValue(orderId, out var jsonr))
{
// CheckFreshJsTiket();
// string text =
// "jsapi_ticket="+jstiket+ "&noncestr=" + jsonr["nonceStr"].ToString()
// +"&timestamp=" + jsonr["timeStamp"].ToString() + "&url="+url+ "";
// var sign = HashHelper.SHA1String(text);
string sign = "";
string text = "";
string ret = jsoncallback + "([0,"
+ "'" + jsonr["appId"].ToString() + "',"
+ "'" + jsonr["timeStamp"].ToString() + "',"
+ "'" + jsonr["nonceStr"].ToString() + "',"
+ "'" + jsonr["package"].ToString() + "',"
+ "'" + jsonr["signType"].ToString() + "',"
+ "'" + jsonr["paySign"].ToString() + "',"
+ "'" + sign + "'"
+ "])"
;
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes(ret) };
HttpServer.SendResponse(httpCtx);
//order_cache.Remove(orderId, out var _);
TraceLog.Trace("ret {0}, sign {1}, text {2}", ret, sign, text);
}
else
{
string ret = jsoncallback+ "([-1, \"订单已经过期,请重新下单\"])";
httpCtx.httpResponse = new HttpResponse { StatusCode = ((int)HttpErrorStatusCode.Success).ToString(), Content = Encoding.UTF8.GetBytes(ret) };
HttpServer.SendResponse(httpCtx);
}
}
public static void PayWsjsapiReq(uint remoteAppID, StructPacket packet)
{
ref var req = ref packet.GetMessage<CSWXJSPayReq>();
TraceLog.Trace("HttpProxyPayMsgHandler.PayWsjsapiReq uid {0}", req.Uid);
JObject jsonData = JObject.Parse(req.DataJson.GetString());
//JsonData jsonData = JsonMapper.ToObject("{}");
string out_trade_no = jsonData["out_trade_no"].ToString();
jsonData["appid"] = HttpProxyPayServerUtils.GetServerConfig().wxAppId;
jsonData["mchid"] = HttpProxyPayServerUtils.GetServerConfig().mchid;
HttpProxyPayServerUtils.GetServerConfig().payUrls.ForEach((payUrl) =>
{
if (payUrl.payId == HttpProxyPayServerUtils.GetServerConfig().selfPayId)
{
jsonData["notify_url"] = payUrl.url;
}
});
//jsonData["notify_url"] = HttpProxyPayServerUtils.GetServerConfig().wxJsPayBack;
string body = jsonData.ToString();
var ri = HttpProxyPayServerUtils.GetApp().Rand.Next(100000, 999999);
var now = HttpProxyPayServerUtils.GetTimeSecond();
string text = "POST\n/v3/pay/transactions/jsapi\n" + now + "\n" + ri + "\n" + body + "\n";
var sign = SHARSASign.SignWithSHA256RSA(text, HttpProxyPayServerUtils.GetServerConfig().wxPayPem);
string auth = "mchid=\"" + HttpProxyPayServerUtils.GetServerConfig().mchid + "\",nonce_str=\"" + ri +
"\",signature=\"" + sign + "\",timestamp=\"" + now + "\",serial_no=\"" + HttpProxyPayServerUtils.GetServerConfig().wxPayPemNo + "\"";
TraceLog.Trace("sign={0}, text={1}", sign, text);
//prepay
string url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
StringContent content = new StringContent(body, Encoding.UTF8, "application/json");
List<KeyValuePair<String, String>> headerList = new List<KeyValuePair<string, string>>();
headerList.Add(new KeyValuePair<string, string>("Authorization", "WECHATPAY2-SHA256-RSA2048 " + auth));
headerList.Add(new KeyValuePair<string, string>("Accept", "application/json"));
headerList.Add(new KeyValuePair<string, string>("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"));
//headerList.Add(new KeyValuePair<string, string>("Content-Type", "application/json"));
string ret = HttpUtils.HttpPost(url, content, headerList, out var ex);
if (ret != "")
{
TraceLog.Trace("ret ={0}", ret);
JsonData jsonr = JsonMapper.ToObject(ret);
if (jsonr.ContainsKey("prepay_id"))
{
string prepayid = jsonr["prepay_id"].ToString();
//var res = new CSWXJSPayReS();
//res.PrepayId.SetString(prepayid);
jsonr["appId"] = HttpProxyPayServerUtils.GetServerConfig().wxAppId;
jsonr["timeStamp"] = now;
jsonr["nonceStr"] = ri;
jsonr["package"] = "prepay_id=" + prepayid;
jsonr["signType"] = "RSA";
string jtext = ""+ HttpProxyPayServerUtils.GetServerConfig().wxAppId + "\n" + now + "\n"+ri+ "\nprepay_id=" + prepayid+"\n";
string jsign = SHARSASign.SignWithSHA256RSA(jtext, HttpProxyPayServerUtils.GetServerConfig().wxPayPem);
jsonr["paySign"] = jsign;
//res.JsApiData.SetString(jsonr.ToJson());
//HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(remoteAppID, (int)CSGameMsgID.PayWsjsapiRes,
// ref res, packet.ObjectID);
//放入缓存等待拉取
order_cache.TryAdd(out_trade_no, jsonr);
TraceLog.Trace("add order_cache add {0} = {1}, jtext={2}", out_trade_no, jsonr.ToJson(), jtext);
}
}
}
private static void CheckFreshJsTiket(bool force = false)
{
CheckFreshAccessToken();
long now = HttpProxyPayServerUtils.GetTimeSecond();
if (now > tiketExpire || force)
{
string url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
string ret = HttpUtils.HttpGet(url, out bool exception,null );
TraceLog.Debug("WXHandler.CheckFreshJsTiket, get ret:{0}", ret);
if (ret == null)
{
return;
}
LitJson.JsonData jsonData = JsonMapper.ToObject(ret);
jstiket = jsonData["ticket"].ToString();
tiketExpire = now + ((long)jsonData["expires_in"]);
}
}
public static void HomeMiniJSAPICallBack(HttpContext httpCtx)
{
TraceLog.Trace("HeroPayHttpHandler.HomeMiniJSAPICallBack 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);
foreach (var e in httpCtx.httpRequest.Headers)
{
TraceLog.Trace("HeroPayHttpHandler.HomeMiniJSAPICallBack header {0} {1}", e.Key, e.Value);
}
var Wechatpay_Timestamp = "";
if (httpCtx.httpRequest.Headers.ContainsKey("Wechatpay-Timestamp"))
{
Wechatpay_Timestamp = httpCtx.httpRequest.Headers["Wechatpay-Timestamp"];
}
else
{
Wechatpay_Timestamp = httpCtx.httpRequest.Headers["wechatpay-timestamp"];
}
Wechatpay_Timestamp = Wechatpay_Timestamp.Trim();
var Wechatpay_Nonce = "";
if (httpCtx.httpRequest.Headers.ContainsKey("Wechatpay_Nonce"))
{
Wechatpay_Nonce = httpCtx.httpRequest.Headers["Wechatpay_Nonce"];
}
else
{
Wechatpay_Nonce = httpCtx.httpRequest.Headers["wechatpay-nonce"];
}
Wechatpay_Nonce = Wechatpay_Nonce.Trim();
var Wechatpay_Signature = "";
if (httpCtx.httpRequest.Headers.ContainsKey("Wechatpay_Signature"))
{
Wechatpay_Signature = httpCtx.httpRequest.Headers["Wechatpay_Signature"];
}
else
{
Wechatpay_Signature = httpCtx.httpRequest.Headers["wechatpay-signature"];
}
Wechatpay_Signature = Wechatpay_Signature.Trim();
var Wechatpay_Serial = "";
if (httpCtx.httpRequest.Headers.ContainsKey("Wechatpay_Serial"))
{
Wechatpay_Serial = httpCtx.httpRequest.Headers["Wechatpay_Serial"];
}
else
{
Wechatpay_Serial = httpCtx.httpRequest.Headers["wechatpay-serial"];
}
string text = Wechatpay_Timestamp + "\n" + Wechatpay_Nonce + "\n" + httpCtx.httpRequest.Content + "\n";
if (!SHARSASign.VerifyWithSHA256RSA(text, HttpProxyPayServerUtils.GetServerConfig().wxPayPubPem, Wechatpay_Signature))
{
TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack VerifyWithSHA256RSA fail text={0}, sig={1}", text, Wechatpay_Signature);
return;
}
JsonData jsonData = JsonMapper.ToObject(httpCtx.httpRequest.Content);
if (jsonData.ContainsKey("event_type") && jsonData["event_type"].ToString() == "TRANSACTION.SUCCESS")
{
JsonData resource = jsonData["resource"];
string ciphertext = resource["ciphertext"].ToString();
string associated_data = resource["associated_data"].ToString();
string nonce = resource["nonce"].ToString();
string sMsg = SHARSASign.AesGcmDecrypt(HttpProxyPayServerUtils.GetServerConfig().wxV3Key, associated_data, nonce, ciphertext);
TraceLog.Trace("HeroPayHttpHandler.HomeMiniJSAPICallBack sMsg {0}", sMsg);
resource = JsonMapper.ToObject(sMsg);
JsonData amount = resource["amount"];
string out_trade_no = resource["out_trade_no"].ToString();
string transaction_id = resource["transaction_id"].ToString();
string trade_state = resource["trade_state"].ToString();
string payer_total = amount["payer_total"].ToString();
string[] split = out_trade_no.Split('-');
int payUrlId = 0;
if (split.Length >= 9)
{
string strpayUrlId = split[8];
if (!string.IsNullOrEmpty(strpayUrlId))
{
if (!int.TryParse(strpayUrlId, out payUrlId))
{
TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack invalid payUrlId {0}", strpayUrlId);
return;
}
}
}
var svrData = HttpProxyPayServerUtils.GetHttpProxyServerData();
if (payUrlId > 0 && payUrlId != svrData.selfPayId)
{//jsapi不应该需要中转
TraceLog.Trace("HeroPayHttpHandler.HomeMiniJSAPICallBack orderId {0} payUrlId {1} no url", out_trade_no, payUrlId);
return;
}
//if (!int.TryParse(split[5], out int payParam1))
//{
// TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack invalid payParam1 {0}", split[5]);
// payParam1 = (int)PayUtils.GetParam1FromOrderId(out_trade_no);
// if (payParam1 >= 0)
// {
// TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack invalid payParam1 {0} {1}", split[5], payParam1);
// return;
// }
//}
//if (!int.TryParse(split[6], out int payParam2))
//{
// TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack invalid payParam2 {0}", split[6]);
// return;
//}
if (!long.TryParse(split[0], out long uid))
{
TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack invalid uid {0}", split[0]);
return;
}
if (!HttpContextCache.AddContext(httpCtx))
{
TraceLog.Error("HeroPayHttpHandler.HomeMiniJSAPICallBack add httpContext failed, ctx id {0}", httpCtx.id);
return;
}
order_cache.TryRemove(out_trade_no, out var _ );
DateTimeOffset dateTimeOffset = DateTimeOffset.Parse(resource["success_time"].ToString());
// 如果你想将其转换为 UTC 时间,可以调用 .UtcDateTime 属性
DateTime utcTime = dateTimeOffset.DateTime;
var CreateTime = AppTime.ConvertDateTimeToUnixTime(utcTime)/1000;
httpCtx.callbackArgs = new HeroPayCallbackArgs() { orderId = out_trade_no,
status = HeroPayCallbackStatus.paySucc
};
int subPayType = (int)PayType.MiniPay;
var req = new SSPayGoogleSuccessReq { Uid = uid, PayType = (int)PayType.MiniPay, CheckSuccess3rd = 1 };
req.HttpCtxId = httpCtx.id;
req.ItemID = int.Parse(split[4]);
req.PurchaseData.SetString(sMsg);
req.Signature.SetString("");
req.OrderId.SetString(out_trade_no);
req.OrderId3rd.SetString(transaction_id);
req.PayParam1 = 0;
req.PayParam2 = 0;
req.GmTestPay = false;
req.Amount = Convert.ToUInt32(payer_total) ;//分-》元
req.Currency.SetString("CNY"); // 币种
req.SubPayType = subPayType;
req.PayTime3rd = CreateTime;
req.Sandbox = 0;
// 如果第三方时间解析不出来就用服务器当前时间
if (req.PayTime3rd == 0)
{
req.PayTime3rd = HttpProxyPayServerUtils.GetTimeSecond();
}
uint dbServerID = DBServerSelect.GetDBServerID(uid);
HttpProxyPayServerUtils.GetPacketSender().SendToServerByID(dbServerID, (int)SSGameMsgID.PayGoogleSuccessReq, ref req, uid);
}
}
}
}