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.
340 lines
17 KiB
340 lines
17 KiB
1 month ago
|
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()
|
||
|
// +"×tamp=" + 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);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|