[//统一返回 async function( kuo,Context,context){ Context.headers["content-type"] = 'application/json; charset=UTF-8'; let $THIS = this; let $features = await Kuoplus(kuo.class); let $LANG = this.LANG(); let $DATA = Object.assign({},this.$DATA); let $_POST = kuo.post; let $_GET = kuo.get; let $method =kuo.Path['0']&&kuo.Path['0'] != ""?kuo.Path['0']:"submit"; let $filename = kuo.func_; let $PAYHTTP = 'https://api.mch.weixin.qq.com/v3/pay/transactions/native'; //支付发起地址 let $PAYYB = KuoLink(["pay",$filename,"notify"]); let $PAYTB = KuoLink(["pay",$filename,"return"]); let $APPID = $features['configure'][$filename]?$features['configure'][$filename]['0']:""; //公众号ID let $MCHID = $features['configure'][$filename]?$features['configure'][$filename]['1']:"";//mchid let $APPKEY = $features['configure'][$filename]?$features['configure'][$filename]['2']:""; //私钥 let $SERIAL = $features['configure'][$filename]?$features['configure'][$filename]['3']:"";//证书id let $V3KEY = $features['configure'][$filename]?$features['configure'][$filename]['4']:"";//v3 密钥 if($method == 'return'){ //同步返回 let uuul = $features['configure']['同步跳转']?$features['configure']['同步跳转']:[]; Context.statusCode = 302; Context.headers["Location"] = KuoLink(uuul)+'?out_trade_no='+$_GET['out_trade_no']; Context.body = ""; return ; }else if($method == 'notify'){ let BODY = kuo.body ; let HEAD = kuo.headers; let $wenxinzznegshu = await Mem.Get("weixinzhengshu"); if(!$wenxinzznegshu){ $wenxinzznegshu = {}; let $canonical_url = "/v3/certificates"; let $timestamp = Mode("Tools").Time(); let $nonce = Md5(Mode("Tools").Uuid()); let $message = "GET\n"+ $canonical_url+"\n"+ $timestamp+"\n"+ $nonce+"\n\n"; let $sign = SHA256_sign($message,$APPKEY); let $Authorization = mchid="${$MCHID}",serial_no="${$SERIAL}",nonce_str="${$nonce}",timestamp="${$timestamp}",signature="${$sign}"; let $fan = await GET("https://api.mch.weixin.qq.com/v3/certificates",{ headers:{ "Content-Type":"application/json", "Accept":"application/json", 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36', "Authorization": "WECHATPAY2-SHA256-RSA2048 "+$Authorization } }); $fan = json_decode($fan,true); if($fan && $fan['data']){ for(var xx in $fan['data']){ var tazhi = $fan['data'][xx]; let $resource = tazhi['encrypt_certificate']; let cipherText = Buffer.from( $resource['ciphertext'],'base64'); var decipher = CRYPTO.createDecipheriv('aes-256-gcm', $V3KEY , $resource['nonce']); let authTag = cipherText.slice(cipherText.length - 16); let data = cipherText.slice(0, cipherText.length - 16); decipher.setAuthTag(authTag); let rst = decipher.update(data, 'binary', 'utf8'); try { rst += decipher.final('utf-8'); } catch (e) {} const x509_1 = require('@fidm/x509'); const certificate = x509_1.Certificate.fromPEM(rst); let xxx = certificate.publicKeyRaw.toString('base64'); $wenxinzznegshu[tazhi.serial_no] = xxx; } await Mem.Set("weixinzhengshu",$wenxinzznegshu,3600*24); } } let $wechatpay_serial =kuo.headers["wechatpay-serial"]?kuo.headers["wechatpay-serial"]:reset($wenxinzznegshu); if(!$wechatpay_serial){ Context.body = 'fail'; return ; } let qiankey = $wenxinzznegshu[$wechatpay_serial]; if(!qiankey){ Context.body = 'fail'; return ; } let $message = HEAD['wechatpay-timestamp']+"\n"+ HEAD['wechatpay-nonce']+"\n"+ BODY+"\n"; let fanx = SHA256_verify($message, HEAD['wechatpay-signature'] , qiankey); if(!fanx){ Context.body = 'fail'; return ; } BODY = json_decode(BODY); if(BODY && BODY['resource']){ let cipherText = Buffer.from( BODY.resource['ciphertext'],'base64'); var decipher = CRYPTO.createDecipheriv('aes-256-gcm', $V3KEY , BODY.resource['nonce']); let authTag = cipherText.slice(cipherText.length - 16); let data = cipherText.slice(0, cipherText.length - 16); decipher.setAuthTag(authTag); let rst = decipher.update(data, 'binary', 'utf8'); try { rst += decipher.final('utf-8'); } catch (e) {} rst = json_decode(rst); if(rst && rst.trade_state == "SUCCESS"){ let $canonical_url = "/v3/pay/transactions/id/"+rst['transaction_id']+'?mchid='+$MCHID; let $timestamp = Mode("Tools").Time(); let $nonce = Md5(Mode("Tools").Uuid()); let $message = "GET\n"+ $canonical_url+"\n"+ $timestamp+"\n"+ $nonce+"\n\n"; let $sign = SHA256_sign($message,$APPKEY); let $Authorization = mchid="${$MCHID}",serial_no="${$SERIAL}",nonce_str="${$nonce}",timestamp="${$timestamp}",signature="${$sign}"; let $fanxxx = await GET("https://api.mch.weixin.qq.com/v3/pay/transactions/id/"+rst['transaction_id']+'?mchid='+$MCHID,{ headers:{ "Content-Type":"application/json", "Accept":"application/json", 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36', "Authorization": "WECHATPAY2-SHA256-RSA2048 "+$Authorization } }); $fanxxx = json_decode($fanxxx); if(!$fanxxx || !$fanxxx['amount']){ Context.body = 'fail'; return ; } if(rst['amount']['total'] != $fanxxx['amount']['total'] ){ Context.body = 'fail'; return ; } if(rst['amount']['payer_total'] != $fanxxx['amount']['payer_total'] ){ Context.body = 'fail'; return ; } await $THIS.UnifiedBack({ 'out_trade_no': $fanxxx['out_trade_no'], 'money':$fanxxx['amount']['payer_total']/100, 'transaction_id':$fanxxx['transaction_id'], 'huomoney':$fanxxx['amount']['total']/100 }); Context.body = 'success'; return ; } Context.body = 'fail'; return ; } Context.body = 'fail'; return ; }else{ //提交订单 if($APPID == "" || $APPKEY == ""){ $DATA.code = -1;$DATA.msg = $LANG.tong_off;Context.body = JSON.stringify($DATA); return ; } let $ORDER = null; let $db = await db('pay_payment'); if($method == 'submit'){ let $Security = await Mem.Get("session/"+kuo.sessionid); if(!$Security ){ $Security = {'uid':0}; } if(!$Security || !$Security['uid'] || $Security['uid'] < 1){ $DATA.code = -1;$DATA.msg = $LANG.no_login;Context.body = JSON.stringify($DATA); return ; } let $type = 1; let $money = $_GET['money']?$_GET['money']:1; if($money <= 0){ $money = 1; } $ORDER = await $THIS.PayMent_Add({ 'uid':$Security['uid'], 'type': $type , 'money': $money, 'plus': kuo.class, 'remarks': $_GET['remarks']??'' , 'ip':kuo.ip, 'agent':kuo.agent }); }else{ let $safe = await Mem.Add("orderid/"+$method,1,$THIS.$findtime ); if($safe > $THIS.$safenum ){ $DATA.code = -1;$DATA.msg = $LANG.shouhoufang;Context.body = JSON.stringify($DATA); return ; } $ORDER = await $db.Where({'out_trade_no': $method}).Find(); } if(!$ORDER){ $DATA.code = -1;$DATA.msg = $LANG.add_no;Context.body = JSON.stringify($DATA); return ; } if($ORDER['off'] != 0){ $DATA.code = -1;$DATA.msg = $LANG.off_error;Context.body = JSON.stringify($DATA); return ; } await $db.Where({'id': $ORDER['id']}).Update({off:1}); let $shuju ={ 'appid' : $APPID, 'mchid' : $MCHID, 'description': $ORDER['subject'] == ''?"pay":$ORDER['subject'], 'out_trade_no':$ORDER['out_trade_no'], 'notify_url':$PAYYB, 'amount':{ 'total': $ORDER['money'] *100 }, 'scene_info':{ 'payer_client_ip':kuo.ip } }; $shuju = json_encode($shuju); let $canonical_url = "/v3/pay/transactions/native"; let $timestamp = Mode("Tools").Time(); let $nonce = Md5(Mode("Tools").Uuid()); let $message = "POST\n"+ $canonical_url+"\n"+ $timestamp+"\n"+ $nonce+"\n"+ $shuju+"\n"; let $sign = SHA256_sign($message,$APPKEY); let $Authorization = mchid="${$MCHID}",serial_no="${$SERIAL}",nonce_str="${$nonce}",timestamp="${$timestamp}",signature="${$sign}"; var $fan = await POST($PAYHTTP ,$shuju ,{ formData:null, body: $shuju, headers:{ "Content-Type":"application/json", "Accept":"application/json", 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36', "Authorization": "WECHATPAY2-SHA256-RSA2048 "+$Authorization } }); $fan = json_decode($fan); if($fan && $fan['code']){ $DATA.code = -1;$DATA.msg = $fan['message'];Context.body = JSON.stringify($DATA); return ; } let EWM = $fan['code_url']; let uuul = $features['configure']['同步跳转']?$features['configure']['同步跳转']:[]; let CHENGGON = KuoLink(uuul)+'?out_trade_no='+$ORDER['out_trade_no']; let KUOchaurl = KuoLink(["pay","find"])+'?out_trade_no='+$ORDER['out_trade_no']; Context.headers["content-type"] = 'text/html; charset=UTF-8'; Context.body = EWM; return ; } } ]