提交 bd8bec0c 编写于 作者: VK1688's avatar VK1688

uni-pay新增苹果虚拟支付

上级 2f557bd4
......@@ -1037,6 +1037,13 @@
"enablePullDownRefresh": false
}
},
{
"path": "pages/API/virtual-payment/virtual-payment-uni-pay",
"style": {
"navigationBarTitleText": "苹果虚拟支付(uni-pay)",
"enablePullDownRefresh": false
}
},
// #endif
{
"path": "pages/API/request-payment/request-payment/order-detail",
......@@ -1798,14 +1805,14 @@
{
"path": "uni_modules/uni-pay-x/pages/ad-interactive-webview/ad-interactive-webview",
"style": {
"navigationBarTitleText": "收银台",
"navigationBarTitleText": "ad",
"backgroundColor": "#F8F8F8"
}
},
{
"path": "uni_modules/uni-pay-x/pages/pay-desk/pay-desk",
"style": {
"navigationBarTitleText": "ad",
"navigationBarTitleText": "收银台",
"backgroundColor": "#F8F8F8"
}
},
......
......@@ -27,9 +27,12 @@
<!-- #endif -->
<button class="button" @click="getOrderPopup(true)">查询支付状态</button>
<button class="button" @click="pageTo('/uni_modules/uni-pay-x/pages/success/success?out_trade_no=test2024030501-1&order_no=test2024030501&total_fee=1&adpid=1000000001&return_url=/pages/API/request-payment-uni-pay/order-detail')">支付成功页面示例</button>
<button class="button" @click="pageTo('/uni_modules/uni-pay-x/pages/success/success?out_trade_no=test2024030501-1&order_no=test2024030501&total_fee=1&adpid=1000000001&return_url=/pages/API/request-payment/request-payment/order-detail')">支付成功页面示例</button>
<!-- #ifdef APP-IOS -->
<button class="button" @click="pageTo('/pages/API/virtual-payment/virtual-payment-uni-pay')">苹果虚拟支付示例(iOS内购)</button>
<!-- #endif -->
<!-- 查询支付的弹窗 -->
<uni-pay-popup ref="getOrderPopupRef" type="bottom">
<uni-pay-popup ref="getOrderPopupRef" type="center">
<scroll-view direction="vertical" class="get-order-popup">
<view class="label">插件支付单号:</view>
<view class="mt20">
......@@ -90,7 +93,7 @@
<button class="button" v-if="h5Env === 'h5-weixin'" @click="getWeiXinJsCode('snsapi_base')">公众号获取openid示例</button>
<!-- #endif -->
<!-- 统一支付组件,注意:vue3下ref不可以等于组件名,因此这里ref="pay" 而不能是 ref="uniPay" -->
<uni-pay ref="payRef" :adpid="adpid" height="900rpx" return-url="/pages/API/request-payment-uni-pay/order-detail" logo="/static/logo.png" @success="onSuccess" @create="onCreate"
<uni-pay ref="payRef" :adpid="adpid" height="900rpx" return-url="/pages/API/request-payment/request-payment/order-detail" logo="/static/logo.png" @success="onSuccess" @create="onCreate"
@fail="onFail" @cancel="onCancel"></uni-pay>
</view>
</template>
......@@ -251,7 +254,7 @@
getOrderData['out_trade_no'] = this.out_trade_no;
}
let res = await payInstance.getOrder(getOrderData);
if (res != null && res['errCode'] == 0) {
if (res['errCode'] == 0) {
this.getOrderRes = res.getJSON('pay_order') as UTSJSONObject;
let obj = {
"-1": "已关闭",
......@@ -275,7 +278,7 @@
let res = await payInstance.refund({
out_trade_no: this.out_trade_no, // 插件支付单号
});
if (res != null && res['errCode'] == 0) {
if (res['errCode'] == 0) {
uni.showToast({
title: res['errMsg'] as string,
icon: "none"
......@@ -288,7 +291,7 @@
let res = await payInstance.getRefund({
out_trade_no: this.out_trade_no, // 插件支付单号
});
if (res != null && res['errCode'] == 0) {
if (res['errCode'] == 0) {
uni.showModal({
content: res['errMsg'] as string,
showCancel: false
......@@ -301,7 +304,7 @@
let res = await payInstance.closeOrder({
out_trade_no: this.out_trade_no, // 插件支付单号
});
if (res != null && res['errCode'] == 0) {
if (res['errCode'] == 0) {
uni.showModal({
content: res['errMsg'] as string,
showCancel: false
......@@ -316,7 +319,7 @@
provider: "wxpay",
provider_pay_type: "jsapi"
});
if (res != null && res['appid'] != null && res['appid'] != "") {
if (res['appid'] != null && res['appid'] != "") {
let appid = res['appid'] as string;
let redirect_uri = window.location.href.split("?")[0];
let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=STATE#wechat_redirect`;
......@@ -327,7 +330,7 @@
async getOpenid(data:UTSJSONObject) : Promise<void> {
const payInstance = this.$refs["payRef"] as UniPayComponentPublicInstance;
let res = await payInstance.getOpenid(data);
if (res != null && res['openid'] != null && res['openid'] != "") {
if (res['openid'] != null && res['openid'] != "") {
let openid = res['openid'] as string;
let code = data['code'] as string;
this.openid = openid;
......
<template>
<view class="content">
<view class="uni-list">
<radio-group @change="applePriceChange">
<view class="uni-list-cell" v-for="(item, index) in productList" :key="index">
<radio :value="item['product_id']" :checked="product_id == item['product_id']"/>
<view class="price" @click="applePriceClick(item)">{{item['title']}} {{item['goods_price']}}元</view>
</view>
</radio-group>
</view>
<view class="uni-padding-wrap">
<button class="button btn-pay" @click="createOrder" :loading="loading" :disabled="disabled">立即支付</button>
</view>
<!-- 统一支付组件 -->
<uni-pay ref="payRef" :debug="true" :adpid="adpid" return-url="/pages/API/request-payment/request-payment/order-detail" @mounted="onMounted" @success="onSuccess" @fail="onFail" @cancel="onCancel"></uni-pay>
</view>
</template>
<script>
export default {
data() {
return {
order_no: "", // 业务系统订单号(即你自己业务系统的订单表的订单号)
out_trade_no: "", // 插件支付单号
adpid: "1000000001", // uni-ad的广告位id
loading: false, // 支付按钮是否在loading中
disabled: true, // 支付按钮是否禁用
product_id: "", // 用户选择的商品id
// 出售的苹果虚拟商品列表
productList: [
{
"description": "为DCloud提供的免费软件进行赞助",
"goods_price": 1, // 单价(元)
"buy_quantity": 1, // 数量(消耗性类型: 数量默认是1,最大值是10)
"product_id": "uniappx.consumable.sponsor_1",
"title": "消耗性产品:赞助"
},
{
"description": "为DCloud提供的免费软件进行赞助",
"goods_price": 5, // 单价(元)
"buy_quantity": 1, // 数量(消耗性类型: 数量默认是1,最大值是10)
"product_id": "uniappx.consumable.sponsor_50",
"title": "消耗性产品:赞助"
},
{
"description": "为DCloud提供的免费软件进行赞助",
"goods_price": 1, // 单价(元)
"buy_quantity": 1, // 数量(非消耗性: 数量只能是1,且一个该类型产品一个appleId只能购买一次)
"product_id": "uniappx.nonconsumable.sponsorskin_1",
"title": "非消耗性产品: 赞助"
},
{
"description": "为DCloud提供的免费软件进行赞助",
"goods_price": 1, // 单价(元)
"buy_quantity": 1, // 数量(自动续期订阅产品: 数量只能是1)
"product_id": "uniappx.autorenewable.monthly_1",
"title": "自动续期订阅产品:每月定期赞助", // 注意自动续期订阅产品在沙盒模式下,实际周期会缩短到几分钟续期一次(即现实世界几分钟 = 沙盒世界1个月)
},
{
"description": "为DCloud提供的免费软件进行赞助",
"goods_price": 1, // 单价(元)
"buy_quantity": 1, // 数量(非自动续期订阅产品: 数量只能是1)
"product_id": "uniappx.nonrenewable.monthly_1",
"title": "非自动续期订阅产品:月赞助",
},
{
"description": "为DCloud提供的免费软件进行赞助",
"goods_price": 1, // 单价(元)
"buy_quantity": 1, // 数量
"product_id": "uniappx.nonrenewable.none",
"title": "测试不存在的产品"
}
] as Array<UTSJSONObject>,
}
},
onLoad: function() {
},
onShow() {
},
onUnload() {},
methods: {
// 支付组件加载完毕后执行
onMounted(insideData: any){
this.init();
},
// 初始化
init() {
this.product_id = this.productList[0]["product_id"] as string;
this.disabled = false;
let payRef = this.$refs['payRef'] as UniPayComponentPublicInstance;
// 苹果虚拟支付未完成订单检测
payRef.appleiapRestore();
},
/**
* 发起支付
* 在调用此api前,你应该先创建自己的业务系统订单,并获得订单号 order_no,把order_no当参数传给此api,而示例中为了简化跟支付插件无关的代码,这里直接已时间戳生成了order_no
*/
createOrder(){
this.order_no = `test`+Date.now();
this.out_trade_no = this.order_no;
let productInfo: UTSJSONObject = this.productList.find((item: UTSJSONObject) : boolean => {
return item['product_id'] == this.product_id;
});
let buy_quantity = productInfo.getNumber('buy_quantity') || 1;
let goods_price = productInfo.getNumber('goods_price');
// 发起支付
this.$refs.payRef.createOrder({
provider: "appleiap", // 支付供应商(这里固定为appleiap,代表苹果虚拟支付)
order_no: this.order_no, // 业务系统订单号(即你自己业务系统的订单表的订单号)
out_trade_no: this.out_trade_no, // 插件支付单号
type: "appleiap", // 支付回调类型(可自定义,建议填写appleiap)
description: productInfo.description,
total_fee: parseInt((goods_price * 100 * buy_quantity).toFixed(0)), // 插件是以分为单位,故这里需要乘以100
// apple_virtual字段仅苹果虚拟支付生效
apple_virtual: {
product_id: this.product_id, // 产品id
goods_price: goods_price, // 单价
buy_quantity: buy_quantity, // 购买数量
},
// 自定义数据
custom: {}
});
},
// 监听事件 - 支付成功
onSuccess(res){
console.log('success: ', res);
if (res.user_order_success) {
// 代表用户已付款,且你自己写的回调成功并正确执行了
} else {
// 代表用户已付款,但你自己写的回调执行失败(通常是因为你的回调代码有问题)
}
},
onFail(err){
uni.showModal({
content: `${err.errSubject} : ${err.errCode} : ${err.errMsg}`,
showCancel: false,
title: `发起支付失败`,
});
},
onCancel(err){
uni.showToast({
title: "用户取消了支付",
icon: 'none'
});
},
// 监听-多选框选中的值改变
applePriceChange(e) {
this.product_id = e.detail.value;
},
applePriceClick(item: any){
this.product_id = item['product_id'] as string;
}
}
}
</script>
<style>
.content {
padding: 15px;
}
.button {
background-color: #007aff;
color: #ffffff;
}
.uni-list-cell {
display: flex;
flex-direction: row;
align-items: center;
padding: 10px;
border-bottom: 1px solid #eee;
}
.price {
margin-left: 10px;
}
.btn-pay {
margin-top: 30px;
}
</style>
......@@ -109,12 +109,15 @@ module.exports = {
"alipayRootCertPath": path.join(__dirname, 'alipay/alipayRootCert.crt'), // 支付宝根证书路径
}
},
// ios内购相关(uniapp-x暂不支持)
// 苹果虚拟支付相关
"appleiap": {
// ios内购支付
// 苹果虚拟支付支付,参数获取地址:https://appstoreconnect.apple.com/access/integrations/api/subs
"app": {
"password": "", // App 专用共享密钥,App 专用共享密钥是用于接收此 App 自动续期订阅收据的唯一代码。如果您要将此 App 转让给其他开发者或不想公开主共享密钥,建议使用 App 专用共享密钥。非自动续订场景不需要此参数
"timeout": 10000, // 请求超时时间,单位:毫秒
"appId": "", // 密钥ID
"issuerId": "", // Issuer ID
"bundleId": "", // 正式包名(如果dev包名和正式包名一致,则只填bundleId即可)
"devBundleId": "", // dev包名(如果dev包名和正式包名一致,则devBundleId可不填)
"appCertPath": path.join(__dirname, 'appleiap/apiclient_cert.p8'), // 证书路径
"sandbox": true, // 是否是沙箱环境
},
}
......
<template>
<view class="popup-root" v-if="isOpen" v-show="isShow" @click="clickMask">
<view class="popup-root" :class="'popup-'+type" v-if="isOpen" v-show="isShow" @click="clickMask">
<view @click.stop>
<slot></slot>
</view>
......@@ -20,6 +20,10 @@
type: Boolean,
default: true
},
type: {
type: String,
default: "center"
}
},
watch: {
// 设置show = true 时,如果没有 open 需要设置为 open
......@@ -78,4 +82,7 @@
align-items: center;
z-index: 99;
}
.popup-bottom {
justify-content: flex-end;
}
</style>
\ No newline at end of file
......@@ -264,32 +264,28 @@
options['qr_code'] = false;
options = objectAssign(options, data);
if (options['provider'] == "appleiap") {
// #ifndef APP
// 苹果虚拟支付走特殊逻辑
// #ifdef APP-IOS
return this._appleiapCreateOrder(options);
// #endif
// #ifndef APP-IOS
uni.showModal({
title: "提示",
content: "苹果内购只支持app发起",
content: "请在iOS系统中执行",
showCancel: false
})
// #endif
// #ifdef APP
}
// #ifdef APP
if (options['provider'] == "wxpay") {
// #ifdef uniVersion < 4.11
uni.showModal({
title: "提示",
content: "uni-app x 暂不支持苹果内购",
content: "请先升级HBX至4.11",
showCancel: false
})
// #endif
return;
}
// #ifdef APP
if (options['provider'] == "wxpay") {
// #ifdef uniVersion < 4.11
uni.showModal({
title: "提示",
content: "请先升级HBX至4.11",
showCancel: false
})
return;
// #endif
// #endif
}
// #endif
......@@ -376,15 +372,16 @@
// #ifndef H5
let _order = res.get('order');
let orderStr = typeof _order == "string" ? _order as string : JSON.stringify(_order) as string;
console.log('orderStr: ', orderStr)
uni.requestPayment({
provider: res['provider'] as string,
orderInfo: orderStr,
success: (res : RequestPaymentSuccess) => {
console.log(JSON.stringify(res))
success: (res) => {
console.log("requestPaymentSuccess", JSON.stringify(res))
this._getOrder();
},
fail: (err : RequestPaymentFail) => {
console.log("RequestPaymentFail", JSON.stringify(err))
fail: (err) => {
console.log("requestPaymentFail", JSON.stringify(err))
let errCode = err.errCode;
let errMsg = err.errMsg;
if (errCode == 700713) {
......@@ -399,7 +396,7 @@
this.$emit("fail", err);
}
}
} as RequestPaymentOptions);
});
// #endif
},
// 打开弹窗
......@@ -413,66 +410,99 @@
popupRef.close();
},
// 查询订单(查询支付情况)
async getOrder(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async getOrder(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.getOrder(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 发起退款(此接口需要admin角色才可以访问)
async refund(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async refund(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.refund(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 查询退款(查询退款情况)
async getRefund(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async getRefund(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.getRefund(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 关闭订单
async closeOrder(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async closeOrder(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.closeOrder(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 获取支持的支付供应商
async getPayProviderFromCloud(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async getPayProviderFromCloud(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.getPayProviderFromCloud(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 获取支付配置内的appid(主要用于获取获取微信公众号的appid,用以获取code)
async getProviderAppId(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async getProviderAppId(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.getProviderAppId(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 根据code获取openid
async getOpenid(data : UTSJSONObject) : Promise<UTSJSONObject | null> {
async getOpenid(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.getOpenid(data);
return res;
} catch (err) {
return null
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 验证iosIap苹果内购支付凭据
async verifyReceiptFromAppleiap(data : UTSJSONObject) : Promise<UTSJSONObject> {
try {
let res = await uniPayCo.verifyReceiptFromAppleiap(data);
return res;
} catch (err) {
return {
errCode: -1,
errMsg: (err as Error).message
}
}
},
// 支付成功后的逻辑
......@@ -526,7 +556,7 @@
out_trade_no,
await_notify: true
});
if (res != null) {
if (res['errCode'] == 0) {
let has_paid = res.getBoolean('has_paid');
if (has_paid != null && has_paid == true) {
this.closePopup("qrcodePopup");
......@@ -544,6 +574,173 @@
if (provider != _provider) {
this.createOrder({ provider: provider })
}
},
// 苹果虚拟支付支付逻辑
async _appleiapCreateOrder(options : UTSJSONObject) : Promise<void>{
// #ifndef APP-IOS
uni.showToast({
title: "请在iOS系统中打开",
icon: "none"
})
// #endif
// #ifdef APP-IOS
const virtualPaymentManager = uni.getVirtualPaymentManager();
let createOrderData = {
provider: options.provider,
total_fee: options.total_fee,
order_no: options.order_no,
out_trade_no: options.out_trade_no,
description: options.description,
type: options.type,
apple_virtual: options.apple_virtual,
custom: options.custom,
} as UTSJSONObject;
let res = await uniPayCo.createOrder(createOrderData);
if (res.errCode === 0) {
this.$emit("create", res);
this.res = res;
uni.showLoading({
title: '支付请求中...'
});
try {
// 请求苹果支付
if (this.debug) console.log("正在请求苹果服务器", res.out_trade_no);
uni.requestVirtualPayment({
apple: {
productId: options.getJSON('apple_virtual')!.getString('product_id')!,
appAccountToken: res.appleiap_account_token,
quantity: options.getJSON('apple_virtual')!.getNumber('buy_quantity')! || 1,
},
success: async (requestPaymentRes) => {
uni.hideLoading()
let transaction = requestPaymentRes?.apple;
if (this.debug) console.log('用户支付成功', transaction);
let transactionIdentifier : string = transaction.transactionIdentifier;
let transactionDate : string = transaction.transactionDate;
let outTradeNo : string = res.out_trade_no;
uni.showLoading({
title: '正在处理支付结果...'
});
// 云端请求苹果服务器验证票据
let verifyRes = await this.verifyReceiptFromAppleiap({
out_trade_no: outTradeNo,
transaction_receipt: transaction.jsonRepresentation,
transaction_identifier: transactionIdentifier
});
if (verifyRes.errCode === 0) {
if (verifyRes.repeat) {
uni.showModal({
title: "提示",
content: `当前道具只能购买一次`,
showCancel: false,
confirmText: "好的"
});
} else {
//经过开发者server验证成功后请结束该交易
virtualPaymentManager.finishTransaction({
transaction: transaction,
success: (r) => {
if (this.debug) console.log("关单成功, 该productId= " + transaction.productId)
},
fail: (e) => {
if (this.debug) console.log("关单失败, 该productId= " + transaction.roductId)
}
});
uni.hideLoading();
this.paySuccess(verifyRes);
}
} else {
if (this.debug) console.log('verifyRes: ', verifyRes)
}
},
fail: (err) => {
uni.hideLoading();
if (this.debug) console.log("购买失败:errSubject= " + err.errSubject + ", errCode= " + err.errCode + ", errMsg= " + err.errMsg);
if ([700601].indexOf(err.errCode) > -1 || err.errMsg.indexOf("cancel") > -1) {
this.$emit("cancel", err);
} else {
this.$emit("fail", err);
}
}
});
} catch (err) {
let code = err.errCode || err.code;
if (code === 2) {
// 用户取消支付
if (this.debug) console.log("用户取消支付");
this.$emit("cancel", err);
} else {
// 发起支付失败
console.error("appleiapCreateOrder:fail", err);
this.$emit("fail", err);
}
uni.hideLoading();
}
}
// #endif
},
// 苹果虚拟支付未完成订单检测
appleiapRestore() {
// #ifdef APP-IOS
uni.showLoading({
title: "",
mask: true
});
try {
const virtualPaymentManager = uni.getVirtualPaymentManager();
virtualPaymentManager.getUnfinishedTransactions({
success: async (res) => {
uni.hideLoading()
console.log("获取未结束的订单列表个数:" + res.transactions.length)
res.transactions.forEach(async transaction => {
console.log("getUnfinishedTransactions成功的交易productId= " + transaction.productId);
let appAccountToken : string = transaction.appAccountToken;
let transactionIdentifier : string = transaction.transactionIdentifier;
//let originalTransactionIdentifier : string = transaction.originalTransactionIdentifier;
let transactionDate : string = transaction.transactionDate;
// 云端请求苹果服务器验证票据
let verifyRes = await this.verifyReceiptFromAppleiap({
appleiap_account_token: appAccountToken,
transaction_receipt: transaction.jsonRepresentation,
transaction_identifier: transactionIdentifier,
});
if (verifyRes.errCode === 0 || !appAccountToken) {
// 经过开发者server验证成功后请结束该交易
virtualPaymentManager.finishTransaction({
transaction: transaction,
success: (r) => {
if (this.debug) console.log("关单成功, 该productId= " + transaction.productId)
},
fail: (e) => {
if (this.debug) console.log("关单失败, 该productId= " + transaction.productId)
}
});
uni.hideLoading();
// 如果是自动续期,则不跳页面
if (!verifyRes.is_subscribe && verifyRes.pay_order) {
this.paySuccess(verifyRes);
}
} else {
if (this.debug) console.log('verifyRes: ', verifyRes)
}
})
},
fail: (e) => {
uni.hideLoading()
console.log("获取未结束的订单列表失败:errSubject= " + e.errSubject + ", errCode= " + e.errCode + ", errMsg= " + e.errMsg)
uni.showToast({
title: "获取未结束的订单列表失败:errCode= " + e.errCode,
icon: 'error'
});
}
})
} catch(err){
console.error('err: ', err)
uni.hideLoading()
}
// #endif
}
},
watch: {
......@@ -839,7 +1036,7 @@
margin-bottom: 6rpx;
.qrcode-popup-info-fee {
.text{
.text {
color: red;
font-size: 60rpx;
font-weight: bold;
......
......@@ -15,6 +15,8 @@ const ERROR = {
51009: 51009,
51010: 51010,
51011: 51011,
51012: 51012,
51013: 51013,
// 数据不存在
52001: 52001,
52002: 52002,
......@@ -24,6 +26,8 @@ const ERROR = {
53003: 53003,
53004: 53004,
53005: 53005,
54001: 54001,
54002: 54002,
}
const errSubject = "uni-pay";
......
......@@ -95,6 +95,7 @@ module.exports = {
clientInfo, // 兼容云对象调用云对象模式
cloudInfo, // 兼容云对象调用云对象模式
wxpay_virtual, // 仅用于微信虚拟支付
apple_virtual, // 仅用于苹果虚拟支付
} = data;
if (!clientInfo) clientInfo = this.getClientInfo();
......@@ -118,6 +119,7 @@ module.exports = {
clientInfo,
cloudInfo,
wxpay_virtual,
apple_virtual,
});
// uniappx-特殊处理
if (typeof res.order === "object" && typeof res.order["timestamp"] === "string") {
......@@ -266,13 +268,17 @@ module.exports = {
async verifyReceiptFromAppleiap(data) {
let {
out_trade_no,
appleiap_account_token,
transaction_receipt,
transaction_identifier,
} = data;
const clientInfo = this.getClientInfo();
return await service.pay.verifyReceiptFromAppleiap({
out_trade_no,
appleiap_account_token,
transaction_receipt,
transaction_identifier
transaction_identifier,
clientInfo,
});
},
......@@ -289,5 +295,26 @@ module.exports = {
cloudInfo
});
},
/**
* 请求微信小程序虚拟支付API
*/
async requestWxpayVirtualApi(data) {
const clientInfo = this.getClientInfo();
if (clientInfo.source !== "function") {
throw new Error("requestWxpayVirtualApi只能通过云端调云端的方式调用");
}
let res = await service.pay.requestWxpayVirtualApi(data);
return res;
},
/**
* 测试请求,仅为了确保是否请求能调通
*/
async test(data) {
return {
errCode: 0,
errMsg: "ok"
};
},
}
}
\ No newline at end of file
......@@ -16,6 +16,7 @@ const sentence = {
51010: 'Invalid out_trade_no or transaction_id',
51011: 'Invalid wxpay_virtual',
51012: 'Invalid buy_quantity',
51013: 'Invalid apple_virtual',
52001: 'NotExist payOrder',
52002: 'NotExist notifyUrl',
53001: 'Create payment error',
......
......@@ -15,7 +15,8 @@ const sentence = {
51009: 'cloudInfo不能为空',
51010: '支付单号或第三方交易单号不能同时为空',
51011: '微信虚拟支付参数(wxpay_virtual)不能为空',
51012: '代币购买数量(buy_quantity)不能为空',
51012: '购买数量(buy_quantity)不能为空',
51013: '苹果虚拟支付参数(apple_virtual)不能为空',
52001: '支付订单不存在',
52002: '请先配置正确的异步回调URL',
53001: '获取支付信息失败,请稍后再试',
......@@ -23,7 +24,7 @@ const sentence = {
53003: '查询退款信息失败,请稍后再试',
53004: '关闭订单失败,请稍后再试',
53005: '证书错误,请检查支付证书',
54001: 'ios内购凭据校验不通过',
54001: '苹果虚拟支付凭据校验不通过',
54002: '订单未支付'
};
......
......@@ -82,6 +82,19 @@ util.aes.decrypt = function(obj) {
return decrypted;
};
util.generateUUID = function() {
// 获取当前时间戳
let timestamp = Date.now().toString(16);
while (timestamp.length < 16) {
timestamp = timestamp + "0";
}
// 生成随机数部分
const randomHex = crypto.randomBytes(10).toString('hex');
// 结合时间戳和随机数,并按照UUID格式排列
const uuid = `${timestamp.slice(0, 8)}-${timestamp.slice(8, 12)}-${randomHex.slice(0, 4)}-${randomHex.slice(4, 8)}-${randomHex.slice(8)}`;
return uuid.toLowerCase();
};
module.exports = util;
// aes192算法 - 加密
......
......@@ -3,11 +3,13 @@ const alipay = require('./alipay');
const common = require('./common');
const qrcode = require('./qrcode'); // 此源码为npm i qrcode的压缩版本
const crypto = require('./crypto');
const jsonwebtoken = require('./jsonwebtoken');
module.exports = {
wxpay,
alipay,
common,
qrcode,
crypto
crypto,
jsonwebtoken
};
"use strict";function _interopDefault(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var buffer=_interopDefault(require("buffer")),stream=_interopDefault(require("stream")),util=_interopDefault(require("util")),crypto=_interopDefault(require("crypto"));function createCommonjsModule(e,r){return e(r={exports:{}},r.exports),r.exports}var safeBuffer=createCommonjsModule((function(e,r){var t=buffer.Buffer;function n(e,r){for(var t in e)r[t]=e[t]}function o(e,r,n){return t(e,r,n)}t.from&&t.alloc&&t.allocUnsafe&&t.allocUnsafeSlow?e.exports=buffer:(n(buffer,r),r.Buffer=o),o.prototype=Object.create(t.prototype),n(t,o),o.from=function(e,r,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return t(e,r,n)},o.alloc=function(e,r,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var o=t(e);return void 0!==r?"string"==typeof n?o.fill(r,n):o.fill(r):o.fill(0),o},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return t(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return buffer.SlowBuffer(e)}})),safeBuffer_1=safeBuffer.Buffer,Buffer$1=safeBuffer.Buffer;function DataStream(e){if(this.buffer=null,this.writable=!0,this.readable=!0,!e)return this.buffer=Buffer$1.alloc(0),this;if("function"==typeof e.pipe)return this.buffer=Buffer$1.alloc(0),e.pipe(this),this;if(e.length||"object"==typeof e)return this.buffer=e,this.writable=!1,process.nextTick(function(){this.emit("end",e),this.readable=!1,this.emit("close")}.bind(this)),this;throw new TypeError("Unexpected data type ("+typeof e+")")}util.inherits(DataStream,stream),DataStream.prototype.write=function(e){this.buffer=Buffer$1.concat([this.buffer,Buffer$1.from(e)]),this.emit("data",e)},DataStream.prototype.end=function(e){e&&this.write(e),this.emit("end",e),this.emit("close"),this.writable=!1,this.readable=!1};var dataStream=DataStream,Buffer$2=buffer.Buffer,SlowBuffer=buffer.SlowBuffer,bufferEqualConstantTime=bufferEq;function bufferEq(e,r){if(!Buffer$2.isBuffer(e)||!Buffer$2.isBuffer(r))return!1;if(e.length!==r.length)return!1;for(var t=0,n=0;n<e.length;n++)t|=e[n]^r[n];return 0===t}bufferEq.install=function(){Buffer$2.prototype.equal=SlowBuffer.prototype.equal=function(e){return bufferEq(this,e)}};var origBufEqual=Buffer$2.prototype.equal,origSlowBufEqual=SlowBuffer.prototype.equal;function getParamSize(e){return(e/8|0)+(e%8==0?0:1)}bufferEq.restore=function(){Buffer$2.prototype.equal=origBufEqual,SlowBuffer.prototype.equal=origSlowBufEqual};var paramBytesForAlg={ES256:getParamSize(256),ES384:getParamSize(384),ES512:getParamSize(521)};function getParamBytesForAlg(e){var r=paramBytesForAlg[e];if(r)return r;throw new Error('Unknown algorithm "'+e+'"')}var paramBytesForAlg_1=getParamBytesForAlg,Buffer$3=safeBuffer.Buffer,MAX_OCTET=128,CLASS_UNIVERSAL=0,PRIMITIVE_BIT=32,TAG_SEQ=16,TAG_INT=2,ENCODED_TAG_SEQ=TAG_SEQ|PRIMITIVE_BIT|CLASS_UNIVERSAL<<6,ENCODED_TAG_INT=TAG_INT|CLASS_UNIVERSAL<<6;function base64Url(e){return e.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}function signatureAsBuffer(e){if(Buffer$3.isBuffer(e))return e;if("string"==typeof e)return Buffer$3.from(e,"base64");throw new TypeError("ECDSA signature must be a Base64 string or a Buffer")}function derToJose(e,r){e=signatureAsBuffer(e);var t=paramBytesForAlg_1(r),n=t+1,o=e.length,i=0;if(e[i++]!==ENCODED_TAG_SEQ)throw new Error('Could not find expected "seq"');var s=e[i++];if(s===(1|MAX_OCTET)&&(s=e[i++]),o-i<s)throw new Error('"seq" specified length of "'+s+'", only "'+(o-i)+'" remaining');if(e[i++]!==ENCODED_TAG_INT)throw new Error('Could not find expected "int" for "r"');var a=e[i++];if(o-i-2<a)throw new Error('"r" specified length of "'+a+'", only "'+(o-i-2)+'" available');if(n<a)throw new Error('"r" specified length of "'+a+'", max of "'+n+'" is acceptable');var u=i;if(i+=a,e[i++]!==ENCODED_TAG_INT)throw new Error('Could not find expected "int" for "s"');var c=e[i++];if(o-i!==c)throw new Error('"s" specified length of "'+c+'", expected "'+(o-i)+'"');if(n<c)throw new Error('"s" specified length of "'+c+'", max of "'+n+'" is acceptable');var f=i;if((i+=c)!==o)throw new Error('Expected to consume entire buffer, but "'+(o-i)+'" bytes remain');var l=t-a,p=t-c,m=Buffer$3.allocUnsafe(l+a+p+c);for(i=0;i<l;++i)m[i]=0;e.copy(m,i,u+Math.max(-l,0),u+a);for(var h=i=t;i<h+p;++i)m[i]=0;return e.copy(m,i,f+Math.max(-p,0),f+c),m=base64Url(m=m.toString("base64"))}function countPadding(e,r,t){for(var n=0;r+n<t&&0===e[r+n];)++n;return e[r+n]>=MAX_OCTET&&--n,n}function joseToDer(e,r){e=signatureAsBuffer(e);var t=paramBytesForAlg_1(r),n=e.length;if(n!==2*t)throw new TypeError('"'+r+'" signatures must be "'+2*t+'" bytes, saw "'+n+'"');var o=countPadding(e,0,t),i=countPadding(e,t,e.length),s=t-o,a=t-i,u=2+s+1+1+a,c=u<MAX_OCTET,f=Buffer$3.allocUnsafe((c?2:3)+u),l=0;return f[l++]=ENCODED_TAG_SEQ,c?f[l++]=u:(f[l++]=1|MAX_OCTET,f[l++]=255&u),f[l++]=ENCODED_TAG_INT,f[l++]=s,o<0?(f[l++]=0,l+=e.copy(f,l,0,t)):l+=e.copy(f,l,o,t),f[l++]=ENCODED_TAG_INT,f[l++]=a,i<0?(f[l++]=0,e.copy(f,l,t)):e.copy(f,l,t+i),f}var ecdsaSigFormatter={derToJose:derToJose,joseToDer:joseToDer},Buffer$4=safeBuffer.Buffer,MSG_INVALID_ALGORITHM='"%s" is not a valid algorithm.\n Supported algorithms are:\n "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" and "none".',MSG_INVALID_SECRET="secret must be a string or buffer",MSG_INVALID_VERIFIER_KEY="key must be a string or a buffer",MSG_INVALID_SIGNER_KEY="key must be a string, a buffer or an object",supportsKeyObjects="function"==typeof crypto.createPublicKey;function checkIsPublicKey(e){if(!Buffer$4.isBuffer(e)&&"string"!=typeof e){if(!supportsKeyObjects)throw typeError(MSG_INVALID_VERIFIER_KEY);if("object"!=typeof e)throw typeError(MSG_INVALID_VERIFIER_KEY);if("string"!=typeof e.type)throw typeError(MSG_INVALID_VERIFIER_KEY);if("string"!=typeof e.asymmetricKeyType)throw typeError(MSG_INVALID_VERIFIER_KEY);if("function"!=typeof e.export)throw typeError(MSG_INVALID_VERIFIER_KEY)}}function checkIsPrivateKey(e){if(!Buffer$4.isBuffer(e)&&"string"!=typeof e&&"object"!=typeof e)throw typeError(MSG_INVALID_SIGNER_KEY)}function checkIsSecretKey(e){if(!Buffer$4.isBuffer(e)){if("string"==typeof e)return e;if(!supportsKeyObjects)throw typeError(MSG_INVALID_SECRET);if("object"!=typeof e)throw typeError(MSG_INVALID_SECRET);if("secret"!==e.type)throw typeError(MSG_INVALID_SECRET);if("function"!=typeof e.export)throw typeError(MSG_INVALID_SECRET)}}function fromBase64(e){return e.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}function toBase64(e){var r=4-(e=e.toString()).length%4;if(4!==r)for(var t=0;t<r;++t)e+="=";return e.replace(/\-/g,"+").replace(/_/g,"/")}function typeError(e){var r=[].slice.call(arguments,1),t=util.format.bind(util,e).apply(null,r);return new TypeError(t)}function bufferOrString(e){return Buffer$4.isBuffer(e)||"string"==typeof e}function normalizeInput(e){return bufferOrString(e)||(e=JSON.stringify(e)),e}function createHmacSigner(e){return function(r,t){checkIsSecretKey(t),r=normalizeInput(r);var n=crypto.createHmac("sha"+e,t);return fromBase64((n.update(r),n.digest("base64")))}}function createHmacVerifier(e){return function(r,t,n){var o=createHmacSigner(e)(r,n);return bufferEqualConstantTime(Buffer$4.from(t),Buffer$4.from(o))}}function createKeySigner(e){return function(r,t){checkIsPrivateKey(t),r=normalizeInput(r);var n=crypto.createSign("RSA-SHA"+e);return fromBase64((n.update(r),n.sign(t,"base64")))}}function createKeyVerifier(e){return function(r,t,n){checkIsPublicKey(n),r=normalizeInput(r),t=toBase64(t);var o=crypto.createVerify("RSA-SHA"+e);return o.update(r),o.verify(n,t,"base64")}}function createPSSKeySigner(e){return function(r,t){checkIsPrivateKey(t),r=normalizeInput(r);var n=crypto.createSign("RSA-SHA"+e);return fromBase64((n.update(r),n.sign({key:t,padding:crypto.constants.RSA_PKCS1_PSS_PADDING,saltLength:crypto.constants.RSA_PSS_SALTLEN_DIGEST},"base64")))}}function createPSSKeyVerifier(e){return function(r,t,n){checkIsPublicKey(n),r=normalizeInput(r),t=toBase64(t);var o=crypto.createVerify("RSA-SHA"+e);return o.update(r),o.verify({key:n,padding:crypto.constants.RSA_PKCS1_PSS_PADDING,saltLength:crypto.constants.RSA_PSS_SALTLEN_DIGEST},t,"base64")}}function createECDSASigner(e){var r=createKeySigner(e);return function(){var t=r.apply(null,arguments);return t=ecdsaSigFormatter.derToJose(t,"ES"+e)}}function createECDSAVerifer(e){var r=createKeyVerifier(e);return function(t,n,o){return n=ecdsaSigFormatter.joseToDer(n,"ES"+e).toString("base64"),r(t,n,o)}}function createNoneSigner(){return function(){return""}}function createNoneVerifier(){return function(e,r){return""===r}}supportsKeyObjects&&(MSG_INVALID_VERIFIER_KEY+=" or a KeyObject",MSG_INVALID_SECRET+="or a KeyObject");var jwa=function(e){var r={hs:createHmacSigner,rs:createKeySigner,ps:createPSSKeySigner,es:createECDSASigner,none:createNoneSigner},t={hs:createHmacVerifier,rs:createKeyVerifier,ps:createPSSKeyVerifier,es:createECDSAVerifer,none:createNoneVerifier},n=e.match(/^(RS|PS|ES|HS)(256|384|512)$|^(none)$/i);if(!n)throw typeError(MSG_INVALID_ALGORITHM,e);var o=(n[1]||n[3]).toLowerCase(),i=n[2];return{sign:r[o](i),verify:t[o](i)}},Buffer$5=buffer.Buffer,tostring=function(e){return"string"==typeof e?e:"number"==typeof e||Buffer$5.isBuffer(e)?e.toString():JSON.stringify(e)},Buffer$6=safeBuffer.Buffer;function base64url(e,r){return Buffer$6.from(e,r).toString("base64").replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}function jwsSecuredInput(e,r,t){t=t||"utf8";var n=base64url(tostring(e),"binary"),o=base64url(tostring(r),t);return util.format("%s.%s",n,o)}function jwsSign(e){var r=e.header,t=e.payload,n=e.secret||e.privateKey,o=e.encoding,i=jwa(r.alg),s=jwsSecuredInput(r,t,o),a=i.sign(s,n);return util.format("%s.%s",s,a)}function SignStream(e){var r=e.secret||e.privateKey||e.key,t=new dataStream(r);this.readable=!0,this.header=e.header,this.encoding=e.encoding,this.secret=this.privateKey=this.key=t,this.payload=new dataStream(e.payload),this.secret.once("close",function(){!this.payload.writable&&this.readable&&this.sign()}.bind(this)),this.payload.once("close",function(){!this.secret.writable&&this.readable&&this.sign()}.bind(this))}util.inherits(SignStream,stream),SignStream.prototype.sign=function(){try{var e=jwsSign({header:this.header,payload:this.payload.buffer,secret:this.secret.buffer,encoding:this.encoding});return this.emit("done",e),this.emit("data",e),this.emit("end"),this.readable=!1,e}catch(e){this.readable=!1,this.emit("error",e),this.emit("close")}},SignStream.sign=jwsSign;var signStream=SignStream,Buffer$7=safeBuffer.Buffer,JWS_REGEX=/^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function safeJsonParse(e){if(isObject(e))return e;try{return JSON.parse(e)}catch(e){return}}function headerFromJWS(e){var r=e.split(".",1)[0];return safeJsonParse(Buffer$7.from(r,"base64").toString("binary"))}function securedInputFromJWS(e){return e.split(".",2).join(".")}function signatureFromJWS(e){return e.split(".")[2]}function payloadFromJWS(e,r){r=r||"utf8";var t=e.split(".")[1];return Buffer$7.from(t,"base64").toString(r)}function isValidJws(e){return JWS_REGEX.test(e)&&!!headerFromJWS(e)}function jwsVerify(e,r,t){if(!r){var n=new Error("Missing algorithm parameter for jws.verify");throw n.code="MISSING_ALGORITHM",n}var o=signatureFromJWS(e=tostring(e)),i=securedInputFromJWS(e);return jwa(r).verify(i,o,t)}function jwsDecode(e,r){if(r=r||{},!isValidJws(e=tostring(e)))return null;var t=headerFromJWS(e);if(!t)return null;var n=payloadFromJWS(e);return("JWT"===t.typ||r.json)&&(n=JSON.parse(n,r.encoding)),{header:t,payload:n,signature:signatureFromJWS(e)}}function VerifyStream(e){var r=(e=e||{}).secret||e.publicKey||e.key,t=new dataStream(r);this.readable=!0,this.algorithm=e.algorithm,this.encoding=e.encoding,this.secret=this.publicKey=this.key=t,this.signature=new dataStream(e.signature),this.secret.once("close",function(){!this.signature.writable&&this.readable&&this.verify()}.bind(this)),this.signature.once("close",function(){!this.secret.writable&&this.readable&&this.verify()}.bind(this))}util.inherits(VerifyStream,stream),VerifyStream.prototype.verify=function(){try{var e=jwsVerify(this.signature.buffer,this.algorithm,this.key.buffer),r=jwsDecode(this.signature.buffer,this.encoding);return this.emit("done",e,r),this.emit("data",e),this.emit("end"),this.readable=!1,e}catch(e){this.readable=!1,this.emit("error",e),this.emit("close")}},VerifyStream.decode=jwsDecode,VerifyStream.isValid=isValidJws,VerifyStream.verify=jwsVerify;var verifyStream=VerifyStream,ALGORITHMS=["HS256","HS384","HS512","RS256","RS384","RS512","PS256","PS384","PS512","ES256","ES384","ES512"],ALGORITHMS_1=ALGORITHMS,sign=signStream.sign,verify=verifyStream.verify,decode=verifyStream.decode,isValid=verifyStream.isValid,createSign=function(e){return new signStream(e)},createVerify=function(e){return new verifyStream(e)},jws={ALGORITHMS:ALGORITHMS_1,sign:sign,verify:verify,decode:decode,isValid:isValid,createSign:createSign,createVerify:createVerify},decode$1=function(e,r){r=r||{};var t=jws.decode(e,r);if(!t)return null;var n=t.payload;if("string"==typeof n)try{var o=JSON.parse(n);null!==o&&"object"==typeof o&&(n=o)}catch(e){}return!0===r.complete?{header:t.header,payload:n,signature:t.signature}:n},JsonWebTokenError=function(e,r){Error.call(this,e),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.name="JsonWebTokenError",this.message=e,r&&(this.inner=r)};JsonWebTokenError.prototype=Object.create(Error.prototype),JsonWebTokenError.prototype.constructor=JsonWebTokenError;var JsonWebTokenError_1=JsonWebTokenError,NotBeforeError=function(e,r){JsonWebTokenError_1.call(this,e),this.name="NotBeforeError",this.date=r};NotBeforeError.prototype=Object.create(JsonWebTokenError_1.prototype),NotBeforeError.prototype.constructor=NotBeforeError;var NotBeforeError_1=NotBeforeError,TokenExpiredError=function(e,r){JsonWebTokenError_1.call(this,e),this.name="TokenExpiredError",this.expiredAt=r};TokenExpiredError.prototype=Object.create(JsonWebTokenError_1.prototype),TokenExpiredError.prototype.constructor=TokenExpiredError;var TokenExpiredError_1=TokenExpiredError,s=1e3,m=60*s,h=60*m,d=24*h,w=7*d,y=365.25*d,ms=function(e,r){r=r||{};var t=typeof e;if("string"===t&&e.length>0)return parse(e);if("number"===t&&isFinite(e))return r.long?fmtLong(e):fmtShort(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function parse(e){if(!((e=String(e)).length>100)){var r=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(r){var t=parseFloat(r[1]);switch((r[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return t*y;case"weeks":case"week":case"w":return t*w;case"days":case"day":case"d":return t*d;case"hours":case"hour":case"hrs":case"hr":case"h":return t*h;case"minutes":case"minute":case"mins":case"min":case"m":return t*m;case"seconds":case"second":case"secs":case"sec":case"s":return t*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return t;default:return}}}}function fmtShort(e){var r=Math.abs(e);return r>=d?Math.round(e/d)+"d":r>=h?Math.round(e/h)+"h":r>=m?Math.round(e/m)+"m":r>=s?Math.round(e/s)+"s":e+"ms"}function fmtLong(e){var r=Math.abs(e);return r>=d?plural(e,r,d,"day"):r>=h?plural(e,r,h,"hour"):r>=m?plural(e,r,m,"minute"):r>=s?plural(e,r,s,"second"):e+" ms"}function plural(e,r,t,n){var o=r>=1.5*t;return Math.round(e/t)+" "+n+(o?"s":"")}var timespan=function(e,r){var t=r||Math.floor(Date.now()/1e3);if("string"==typeof e){var n=ms(e);if(void 0===n)return;return Math.floor(t+n/1e3)}return"number"==typeof e?t+e:void 0},semver=createCommonjsModule((function(e,r){var t;r=e.exports=Y,t="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},r.SEMVER_SPEC_VERSION="2.0.0";var n=Number.MAX_SAFE_INTEGER||9007199254740991,o=r.re=[],i=r.safeRe=[],s=r.src=[],a=0,u=[["\\s",1],["\\d",256],["[a-zA-Z0-9-]",250]];function c(e){for(var r=0;r<u.length;r++){var t=u[r][0],n=u[r][1];e=e.split(t+"*").join(t+"{0,"+n+"}").split(t+"+").join(t+"{1,"+n+"}")}return e}var f=a++;s[f]="0|[1-9]\\d*";var l=a++;s[l]="\\d+";var p=a++;s[p]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var m=a++;s[m]="("+s[f]+")\\.("+s[f]+")\\.("+s[f]+")";var h=a++;s[h]="("+s[l]+")\\.("+s[l]+")\\.("+s[l]+")";var d=a++;s[d]="(?:"+s[f]+"|"+s[p]+")";var v=a++;s[v]="(?:"+s[l]+"|"+s[p]+")";var g=a++;s[g]="(?:-("+s[d]+"(?:\\."+s[d]+")*))";var y=a++;s[y]="(?:-?("+s[v]+"(?:\\."+s[v]+")*))";var b=a++;s[b]="[a-zA-Z0-9-]+";var S=a++;s[S]="(?:\\+("+s[b]+"(?:\\."+s[b]+")*))";var E=a++,w="v?"+s[m]+s[g]+"?"+s[S]+"?";s[E]="^"+w+"$";var _="[v=\\s]*"+s[h]+s[y]+"?"+s[S]+"?",j=a++;s[j]="^"+_+"$";var T=a++;s[T]="((?:<|>)?=?)";var I=a++;s[I]=s[l]+"|x|X|\\*";var $=a++;s[$]=s[f]+"|x|X|\\*";var A=a++;s[A]="[v=\\s]*("+s[$]+")(?:\\.("+s[$]+")(?:\\.("+s[$]+")(?:"+s[g]+")?"+s[S]+"?)?)?";var N=a++;s[N]="[v=\\s]*("+s[I]+")(?:\\.("+s[I]+")(?:\\.("+s[I]+")(?:"+s[y]+")?"+s[S]+"?)?)?";var B=a++;s[B]="^"+s[T]+"\\s*"+s[A]+"$";var O=a++;s[O]="^"+s[T]+"\\s*"+s[N]+"$";var k=a++;s[k]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var P=a++;s[P]="(?:~>?)";var R=a++;s[R]="(\\s*)"+s[P]+"\\s+",o[R]=new RegExp(s[R],"g"),i[R]=new RegExp(c(s[R]),"g");var x=a++;s[x]="^"+s[P]+s[A]+"$";var V=a++;s[V]="^"+s[P]+s[N]+"$";var L=a++;s[L]="(?:\\^)";var D=a++;s[D]="(\\s*)"+s[L]+"\\s+",o[D]=new RegExp(s[D],"g"),i[D]=new RegExp(c(s[D]),"g");var G=a++;s[G]="^"+s[L]+s[A]+"$";var M=a++;s[M]="^"+s[L]+s[N]+"$";var J=a++;s[J]="^"+s[T]+"\\s*("+_+")$|^$";var F=a++;s[F]="^"+s[T]+"\\s*("+w+")$|^$";var K=a++;s[K]="(\\s*)"+s[T]+"\\s*("+_+"|"+s[A]+")",o[K]=new RegExp(s[K],"g"),i[K]=new RegExp(c(s[K]),"g");var C=a++;s[C]="^\\s*("+s[A]+")\\s+-\\s+("+s[A]+")\\s*$";var W=a++;s[W]="^\\s*("+s[N]+")\\s+-\\s+("+s[N]+")\\s*$";var H=a++;s[H]="(<|>)?=?\\s*\\*";for(var q=0;q<35;q++)t(q,s[q]),o[q]||(o[q]=new RegExp(s[q]),i[q]=new RegExp(c(s[q])));function U(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof Y)return e;if("string"!=typeof e)return null;if(e.length>256)return null;if(!(r.loose?i[j]:i[E]).test(e))return null;try{return new Y(e,r)}catch(e){return null}}function Y(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof Y){if(e.loose===r.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof Y))return new Y(e,r);t("SemVer",e,r),this.options=r,this.loose=!!r.loose;var o=e.trim().match(r.loose?i[j]:i[E]);if(!o)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>n||this.major<0)throw new TypeError("Invalid major version");if(this.minor>n||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>n||this.patch<0)throw new TypeError("Invalid patch version");o[4]?this.prerelease=o[4].split(".").map((function(e){if(/^[0-9]+$/.test(e)){var r=+e;if(r>=0&&r<n)return r}return e})):this.prerelease=[],this.build=o[5]?o[5].split("."):[],this.format()}r.parse=U,r.valid=function(e,r){var t=U(e,r);return t?t.version:null},r.clean=function(e,r){var t=U(e.trim().replace(/^[=v]+/,""),r);return t?t.version:null},r.SemVer=Y,Y.prototype.format=function(){return this.version=this.major+"."+this.minor+"."+this.patch,this.prerelease.length&&(this.version+="-"+this.prerelease.join(".")),this.version},Y.prototype.toString=function(){return this.version},Y.prototype.compare=function(e){return t("SemVer.compare",this.version,this.options,e),e instanceof Y||(e=new Y(e,this.options)),this.compareMain(e)||this.comparePre(e)},Y.prototype.compareMain=function(e){return e instanceof Y||(e=new Y(e,this.options)),z(this.major,e.major)||z(this.minor,e.minor)||z(this.patch,e.patch)},Y.prototype.comparePre=function(e){if(e instanceof Y||(e=new Y(e,this.options)),this.prerelease.length&&!e.prerelease.length)return-1;if(!this.prerelease.length&&e.prerelease.length)return 1;if(!this.prerelease.length&&!e.prerelease.length)return 0;var r=0;do{var n=this.prerelease[r],o=e.prerelease[r];if(t("prerelease compare",r,n,o),void 0===n&&void 0===o)return 0;if(void 0===o)return 1;if(void 0===n)return-1;if(n!==o)return z(n,o)}while(++r)},Y.prototype.inc=function(e,r){switch(e){case"premajor":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc("pre",r);break;case"preminor":this.prerelease.length=0,this.patch=0,this.minor++,this.inc("pre",r);break;case"prepatch":this.prerelease.length=0,this.inc("patch",r),this.inc("pre",r);break;case"prerelease":0===this.prerelease.length&&this.inc("patch",r),this.inc("pre",r);break;case"major":0===this.minor&&0===this.patch&&0!==this.prerelease.length||this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case"minor":0===this.patch&&0!==this.prerelease.length||this.minor++,this.patch=0,this.prerelease=[];break;case"patch":0===this.prerelease.length&&this.patch++,this.prerelease=[];break;case"pre":if(0===this.prerelease.length)this.prerelease=[0];else{for(var t=this.prerelease.length;--t>=0;)"number"==typeof this.prerelease[t]&&(this.prerelease[t]++,t=-2);-1===t&&this.prerelease.push(0)}r&&(this.prerelease[0]===r?isNaN(this.prerelease[1])&&(this.prerelease=[r,0]):this.prerelease=[r,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},r.inc=function(e,r,t,n){"string"==typeof t&&(n=t,t=void 0);try{return new Y(e,t).inc(r,n).version}catch(e){return null}},r.diff=function(e,r){if(re(e,r))return null;var t=U(e),n=U(r),o="";if(t.prerelease.length||n.prerelease.length){o="pre";var i="prerelease"}for(var s in t)if(("major"===s||"minor"===s||"patch"===s)&&t[s]!==n[s])return o+s;return i},r.compareIdentifiers=z;var X=/^[0-9]+$/;function z(e,r){var t=X.test(e),n=X.test(r);return t&&n&&(e=+e,r=+r),e===r?0:t&&!n?-1:n&&!t?1:e<r?-1:1}function Z(e,r,t){return new Y(e,t).compare(new Y(r,t))}function Q(e,r,t){return Z(e,r,t)>0}function ee(e,r,t){return Z(e,r,t)<0}function re(e,r,t){return 0===Z(e,r,t)}function te(e,r,t){return 0!==Z(e,r,t)}function ne(e,r,t){return Z(e,r,t)>=0}function oe(e,r,t){return Z(e,r,t)<=0}function ie(e,r,t,n){switch(r){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof t&&(t=t.version),e===t;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof t&&(t=t.version),e!==t;case"":case"=":case"==":return re(e,t,n);case"!=":return te(e,t,n);case">":return Q(e,t,n);case">=":return ne(e,t,n);case"<":return ee(e,t,n);case"<=":return oe(e,t,n);default:throw new TypeError("Invalid operator: "+r)}}function se(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof se){if(e.loose===!!r.loose)return e;e=e.value}if(!(this instanceof se))return new se(e,r);e=e.trim().split(/\s+/).join(" "),t("comparator",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===ae?this.value="":this.value=this.operator+this.semver.version,t("comp",this)}r.rcompareIdentifiers=function(e,r){return z(r,e)},r.major=function(e,r){return new Y(e,r).major},r.minor=function(e,r){return new Y(e,r).minor},r.patch=function(e,r){return new Y(e,r).patch},r.compare=Z,r.compareLoose=function(e,r){return Z(e,r,!0)},r.rcompare=function(e,r,t){return Z(r,e,t)},r.sort=function(e,t){return e.sort((function(e,n){return r.compare(e,n,t)}))},r.rsort=function(e,t){return e.sort((function(e,n){return r.rcompare(e,n,t)}))},r.gt=Q,r.lt=ee,r.eq=re,r.neq=te,r.gte=ne,r.lte=oe,r.cmp=ie,r.Comparator=se;var ae={};function ue(e,r){if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),e instanceof ue)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new ue(e.raw,r);if(e instanceof se)return new ue(e.value,r);if(!(this instanceof ue))return new ue(e,r);if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e.trim().split(/\s+/).join(" "),this.set=this.raw.split("||").map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError("Invalid SemVer Range: "+this.raw);this.format()}function ce(e){return!e||"x"===e.toLowerCase()||"*"===e}function fe(e,r,t,n,o,i,s,a,u,c,f,l,p){return((r=ce(t)?"":ce(n)?">="+t+".0.0":ce(o)?">="+t+"."+n+".0":">="+r)+" "+(a=ce(u)?"":ce(c)?"<"+(+u+1)+".0.0":ce(f)?"<"+u+"."+(+c+1)+".0":l?"<="+u+"."+c+"."+f+"-"+l:"<="+a)).trim()}function le(e,r,n){for(var o=0;o<e.length;o++)if(!e[o].test(r))return!1;if(r.prerelease.length&&!n.includePrerelease){for(o=0;o<e.length;o++)if(t(e[o].semver),e[o].semver!==ae&&e[o].semver.prerelease.length>0){var i=e[o].semver;if(i.major===r.major&&i.minor===r.minor&&i.patch===r.patch)return!0}return!1}return!0}function pe(e,r,t){try{r=new ue(r,t)}catch(e){return!1}return r.test(e)}function me(e,r,t,n){var o,i,s,a,u;switch(e=new Y(e,n),r=new ue(r,n),t){case">":o=Q,i=oe,s=ee,a=">",u=">=";break;case"<":o=ee,i=ne,s=Q,a="<",u="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(pe(e,r,n))return!1;for(var c=0;c<r.set.length;++c){var f=r.set[c],l=null,p=null;if(f.forEach((function(e){e.semver===ae&&(e=new se(">=0.0.0")),l=l||e,p=p||e,o(e.semver,l.semver,n)?l=e:s(e.semver,p.semver,n)&&(p=e)})),l.operator===a||l.operator===u)return!1;if((!p.operator||p.operator===a)&&i(e,p.semver))return!1;if(p.operator===u&&s(e,p.semver))return!1}return!0}se.prototype.parse=function(e){var r=this.options.loose?i[J]:i[F],t=e.match(r);if(!t)throw new TypeError("Invalid comparator: "+e);this.operator=t[1],"="===this.operator&&(this.operator=""),t[2]?this.semver=new Y(t[2],this.options.loose):this.semver=ae},se.prototype.toString=function(){return this.value},se.prototype.test=function(e){return t("Comparator.test",e,this.options.loose),this.semver===ae||("string"==typeof e&&(e=new Y(e,this.options)),ie(e,this.operator,this.semver,this.options))},se.prototype.intersects=function(e,r){if(!(e instanceof se))throw new TypeError("a Comparator is required");var t;if(r&&"object"==typeof r||(r={loose:!!r,includePrerelease:!1}),""===this.operator)return t=new ue(e.value,r),pe(this.value,t,r);if(""===e.operator)return t=new ue(this.value,r),pe(e.semver,t,r);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),o=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),i=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=ie(this.semver,"<",e.semver,r)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),u=ie(this.semver,">",e.semver,r)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||o||i&&s||a||u},r.Range=ue,ue.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(" ").trim()})).join("||").trim(),this.range},ue.prototype.toString=function(){return this.range},ue.prototype.parseRange=function(e){var r=this.options.loose,n=r?i[W]:i[C];e=e.replace(n,fe),t("hyphen replace",e),e=e.replace(i[K],"$1$2$3"),t("comparator trim",e,i[K]),e=(e=e.replace(i[R],"$1~")).replace(i[D],"$1^");var o=r?i[J]:i[F],s=e.split(" ").map((function(e){return function(e,r){return t("comp",e,r),e=function(e,r){return e.trim().split(/\s+/).map((function(e){return function(e,r){t("caret",e,r);var n=r.loose?i[M]:i[G];return e.replace(n,(function(r,n,o,i,s){var a;return t("caret",e,r,n,o,i,s),ce(n)?a="":ce(o)?a=">="+n+".0.0 <"+(+n+1)+".0.0":ce(i)?a="0"===n?">="+n+"."+o+".0 <"+n+"."+(+o+1)+".0":">="+n+"."+o+".0 <"+(+n+1)+".0.0":s?(t("replaceCaret pr",s),a="0"===n?"0"===o?">="+n+"."+o+"."+i+"-"+s+" <"+n+"."+o+"."+(+i+1):">="+n+"."+o+"."+i+"-"+s+" <"+n+"."+(+o+1)+".0":">="+n+"."+o+"."+i+"-"+s+" <"+(+n+1)+".0.0"):(t("no pr"),a="0"===n?"0"===o?">="+n+"."+o+"."+i+" <"+n+"."+o+"."+(+i+1):">="+n+"."+o+"."+i+" <"+n+"."+(+o+1)+".0":">="+n+"."+o+"."+i+" <"+(+n+1)+".0.0"),t("caret return",a),a}))}(e,r)})).join(" ")}(e,r),t("caret",e),e=function(e,r){return e.trim().split(/\s+/).map((function(e){return function(e,r){var n=r.loose?i[V]:i[x];return e.replace(n,(function(r,n,o,i,s){var a;return t("tilde",e,r,n,o,i,s),ce(n)?a="":ce(o)?a=">="+n+".0.0 <"+(+n+1)+".0.0":ce(i)?a=">="+n+"."+o+".0 <"+n+"."+(+o+1)+".0":s?(t("replaceTilde pr",s),a=">="+n+"."+o+"."+i+"-"+s+" <"+n+"."+(+o+1)+".0"):a=">="+n+"."+o+"."+i+" <"+n+"."+(+o+1)+".0",t("tilde return",a),a}))}(e,r)})).join(" ")}(e,r),t("tildes",e),e=function(e,r){return t("replaceXRanges",e,r),e.split(/\s+/).map((function(e){return function(e,r){e=e.trim();var n=r.loose?i[O]:i[B];return e.replace(n,(function(r,n,o,i,s,a){t("xRange",e,r,n,o,i,s,a);var u=ce(o),c=u||ce(i),f=c||ce(s);return"="===n&&f&&(n=""),u?r=">"===n||"<"===n?"<0.0.0":"*":n&&f?(c&&(i=0),s=0,">"===n?(n=">=",c?(o=+o+1,i=0,s=0):(i=+i+1,s=0)):"<="===n&&(n="<",c?o=+o+1:i=+i+1),r=n+o+"."+i+"."+s):c?r=">="+o+".0.0 <"+(+o+1)+".0.0":f&&(r=">="+o+"."+i+".0 <"+o+"."+(+i+1)+".0"),t("xRange return",r),r}))}(e,r)})).join(" ")}(e,r),t("xrange",e),e=function(e,r){return t("replaceStars",e,r),e.trim().replace(i[H],"")}(e,r),t("stars",e),e}(e,this.options)}),this).join(" ").split(/\s+/);return this.options.loose&&(s=s.filter((function(e){return!!e.match(o)}))),s=s.map((function(e){return new se(e,this.options)}),this)},ue.prototype.intersects=function(e,r){if(!(e instanceof ue))throw new TypeError("a Range is required");return this.set.some((function(t){return t.every((function(t){return e.set.some((function(e){return e.every((function(e){return t.intersects(e,r)}))}))}))}))},r.toComparators=function(e,r){return new ue(e,r).set.map((function(e){return e.map((function(e){return e.value})).join(" ").trim().split(" ")}))},ue.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new Y(e,this.options));for(var r=0;r<this.set.length;r++)if(le(this.set[r],e,this.options))return!0;return!1},r.satisfies=pe,r.maxSatisfying=function(e,r,t){var n=null,o=null;try{var i=new ue(r,t)}catch(e){return null}return e.forEach((function(e){i.test(e)&&(n&&-1!==o.compare(e)||(o=new Y(n=e,t)))})),n},r.minSatisfying=function(e,r,t){var n=null,o=null;try{var i=new ue(r,t)}catch(e){return null}return e.forEach((function(e){i.test(e)&&(n&&1!==o.compare(e)||(o=new Y(n=e,t)))})),n},r.minVersion=function(e,r){e=new ue(e,r);var t=new Y("0.0.0");if(e.test(t))return t;if(t=new Y("0.0.0-0"),e.test(t))return t;t=null;for(var n=0;n<e.set.length;++n){e.set[n].forEach((function(e){var r=new Y(e.semver.version);switch(e.operator){case">":0===r.prerelease.length?r.patch++:r.prerelease.push(0),r.raw=r.format();case"":case">=":t&&!Q(t,r)||(t=r);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+e.operator)}}))}if(t&&e.test(t))return t;return null},r.validRange=function(e,r){try{return new ue(e,r).range||"*"}catch(e){return null}},r.ltr=function(e,r,t){return me(e,r,"<",t)},r.gtr=function(e,r,t){return me(e,r,">",t)},r.outside=me,r.prerelease=function(e,r){var t=U(e,r);return t&&t.prerelease.length?t.prerelease:null},r.intersects=function(e,r,t){return e=new ue(e,t),r=new ue(r,t),e.intersects(r)},r.coerce=function(e){if(e instanceof Y)return e;if("string"!=typeof e)return null;var r=e.match(i[k]);if(null==r)return null;return U(r[1]+"."+(r[2]||"0")+"."+(r[3]||"0"))}})),semver_1=semver.SEMVER_SPEC_VERSION,semver_2=semver.re,semver_3=semver.safeRe,semver_4=semver.src,semver_5=semver.parse,semver_6=semver.valid,semver_7=semver.clean,semver_8=semver.SemVer,semver_9=semver.inc,semver_10=semver.diff,semver_11=semver.compareIdentifiers,semver_12=semver.rcompareIdentifiers,semver_13=semver.major,semver_14=semver.minor,semver_15=semver.patch,semver_16=semver.compare,semver_17=semver.compareLoose,semver_18=semver.rcompare,semver_19=semver.sort,semver_20=semver.rsort,semver_21=semver.gt,semver_22=semver.lt,semver_23=semver.eq,semver_24=semver.neq,semver_25=semver.gte,semver_26=semver.lte,semver_27=semver.cmp,semver_28=semver.Comparator,semver_29=semver.Range,semver_30=semver.toComparators,semver_31=semver.satisfies,semver_32=semver.maxSatisfying,semver_33=semver.minSatisfying,semver_34=semver.minVersion,semver_35=semver.validRange,semver_36=semver.ltr,semver_37=semver.gtr,semver_38=semver.outside,semver_39=semver.prerelease,semver_40=semver.intersects,semver_41=semver.coerce,psSupported=semver.satisfies(process.version,"^6.12.0 || >=8.0.0"),PUB_KEY_ALGS=["RS256","RS384","RS512","ES256","ES384","ES512"],RSA_KEY_ALGS=["RS256","RS384","RS512"],HS_ALGS=["HS256","HS384","HS512"];psSupported&&(PUB_KEY_ALGS.splice(3,0,"PS256","PS384","PS512"),RSA_KEY_ALGS.splice(3,0,"PS256","PS384","PS512"));var verify$1=function(e,r,t,n){var o;if("function"!=typeof t||n||(n=t,t={}),t||(t={}),t=Object.assign({},t),o=n||function(e,r){if(e)throw e;return r},t.clockTimestamp&&"number"!=typeof t.clockTimestamp)return o(new JsonWebTokenError_1("clockTimestamp must be a number"));if(void 0!==t.nonce&&("string"!=typeof t.nonce||""===t.nonce.trim()))return o(new JsonWebTokenError_1("nonce must be a non-empty string"));var i=t.clockTimestamp||Math.floor(Date.now()/1e3);if(!e)return o(new JsonWebTokenError_1("jwt must be provided"));if("string"!=typeof e)return o(new JsonWebTokenError_1("jwt must be a string"));var s,a=e.split(".");if(3!==a.length)return o(new JsonWebTokenError_1("jwt malformed"));try{s=decode$1(e,{complete:!0})}catch(e){return o(e)}if(!s)return o(new JsonWebTokenError_1("invalid token"));var u,c=s.header;if("function"==typeof r){if(!n)return o(new JsonWebTokenError_1("verify must be called asynchronous if secret or public key is provided as a callback"));u=r}else u=function(e,t){return t(null,r)};return u(c,(function(r,n){if(r)return o(new JsonWebTokenError_1("error in secret or public key callback: "+r.message));var u,f=""!==a[2].trim();if(!f&&n)return o(new JsonWebTokenError_1("jwt signature is required"));if(f&&!n)return o(new JsonWebTokenError_1("secret or public key must be provided"));if(f||t.algorithms||(t.algorithms=["none"]),t.algorithms||(t.algorithms=~n.toString().indexOf("BEGIN CERTIFICATE")||~n.toString().indexOf("BEGIN PUBLIC KEY")?PUB_KEY_ALGS:~n.toString().indexOf("BEGIN RSA PUBLIC KEY")?RSA_KEY_ALGS:HS_ALGS),!~t.algorithms.indexOf(s.header.alg))return o(new JsonWebTokenError_1("invalid algorithm"));try{u=jws.verify(e,s.header.alg,n)}catch(e){return o(e)}if(!u)return o(new JsonWebTokenError_1("invalid signature"));var l=s.payload;if(void 0!==l.nbf&&!t.ignoreNotBefore){if("number"!=typeof l.nbf)return o(new JsonWebTokenError_1("invalid nbf value"));if(l.nbf>i+(t.clockTolerance||0))return o(new NotBeforeError_1("jwt not active",new Date(1e3*l.nbf)))}if(void 0!==l.exp&&!t.ignoreExpiration){if("number"!=typeof l.exp)return o(new JsonWebTokenError_1("invalid exp value"));if(i>=l.exp+(t.clockTolerance||0))return o(new TokenExpiredError_1("jwt expired",new Date(1e3*l.exp)))}if(t.audience){var p=Array.isArray(t.audience)?t.audience:[t.audience];if(!(Array.isArray(l.aud)?l.aud:[l.aud]).some((function(e){return p.some((function(r){return r instanceof RegExp?r.test(e):r===e}))})))return o(new JsonWebTokenError_1("jwt audience invalid. expected: "+p.join(" or ")))}if(t.issuer&&("string"==typeof t.issuer&&l.iss!==t.issuer||Array.isArray(t.issuer)&&-1===t.issuer.indexOf(l.iss)))return o(new JsonWebTokenError_1("jwt issuer invalid. expected: "+t.issuer));if(t.subject&&l.sub!==t.subject)return o(new JsonWebTokenError_1("jwt subject invalid. expected: "+t.subject));if(t.jwtid&&l.jti!==t.jwtid)return o(new JsonWebTokenError_1("jwt jwtid invalid. expected: "+t.jwtid));if(t.nonce&&l.nonce!==t.nonce)return o(new JsonWebTokenError_1("jwt nonce invalid. expected: "+t.nonce));if(t.maxAge){if("number"!=typeof l.iat)return o(new JsonWebTokenError_1("iat required when maxAge is specified"));var m=timespan(t.maxAge,l.iat);if(void 0===m)return o(new JsonWebTokenError_1('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));if(i>=m+(t.clockTolerance||0))return o(new TokenExpiredError_1("maxAge exceeded",new Date(1e3*m)))}if(!0===t.complete){var h=s.signature;return o(null,{header:c,payload:l,signature:h})}return o(null,l)}))},INFINITY=1/0,MAX_SAFE_INTEGER=9007199254740991,MAX_INTEGER=17976931348623157e292,NAN=NaN,argsTag="[object Arguments]",funcTag="[object Function]",genTag="[object GeneratorFunction]",stringTag="[object String]",symbolTag="[object Symbol]",reTrim=/^\s+|\s+$/g,reIsBadHex=/^[-+]0x[0-9a-f]+$/i,reIsBinary=/^0b[01]+$/i,reIsOctal=/^0o[0-7]+$/i,reIsUint=/^(?:0|[1-9]\d*)$/,freeParseInt=parseInt;function arrayMap(e,r){for(var t=-1,n=e?e.length:0,o=Array(n);++t<n;)o[t]=r(e[t],t,e);return o}function baseFindIndex(e,r,t,n){for(var o=e.length,i=t+(n?1:-1);n?i--:++i<o;)if(r(e[i],i,e))return i;return-1}function baseIndexOf(e,r,t){if(r!=r)return baseFindIndex(e,baseIsNaN,t);for(var n=t-1,o=e.length;++n<o;)if(e[n]===r)return n;return-1}function baseIsNaN(e){return e!=e}function baseTimes(e,r){for(var t=-1,n=Array(e);++t<e;)n[t]=r(t);return n}function baseValues(e,r){return arrayMap(r,(function(r){return e[r]}))}function overArg(e,r){return function(t){return e(r(t))}}var objectProto=Object.prototype,hasOwnProperty=objectProto.hasOwnProperty,objectToString=objectProto.toString,propertyIsEnumerable=objectProto.propertyIsEnumerable,nativeKeys=overArg(Object.keys,Object),nativeMax=Math.max;function arrayLikeKeys(e,r){var t=isArray(e)||isArguments(e)?baseTimes(e.length,String):[],n=t.length,o=!!n;for(var i in e)!r&&!hasOwnProperty.call(e,i)||o&&("length"==i||isIndex(i,n))||t.push(i);return t}function baseKeys(e){if(!isPrototype(e))return nativeKeys(e);var r=[];for(var t in Object(e))hasOwnProperty.call(e,t)&&"constructor"!=t&&r.push(t);return r}function isIndex(e,r){return!!(r=null==r?MAX_SAFE_INTEGER:r)&&("number"==typeof e||reIsUint.test(e))&&e>-1&&e%1==0&&e<r}function isPrototype(e){var r=e&&e.constructor;return e===("function"==typeof r&&r.prototype||objectProto)}function includes(e,r,t,n){e=isArrayLike(e)?e:values(e),t=t&&!n?toInteger(t):0;var o=e.length;return t<0&&(t=nativeMax(o+t,0)),isString(e)?t<=o&&e.indexOf(r,t)>-1:!!o&&baseIndexOf(e,r,t)>-1}function isArguments(e){return isArrayLikeObject(e)&&hasOwnProperty.call(e,"callee")&&(!propertyIsEnumerable.call(e,"callee")||objectToString.call(e)==argsTag)}var isArray=Array.isArray;function isArrayLike(e){return null!=e&&isLength(e.length)&&!isFunction(e)}function isArrayLikeObject(e){return isObjectLike(e)&&isArrayLike(e)}function isFunction(e){var r=isObject$1(e)?objectToString.call(e):"";return r==funcTag||r==genTag}function isLength(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=MAX_SAFE_INTEGER}function isObject$1(e){var r=typeof e;return!!e&&("object"==r||"function"==r)}function isObjectLike(e){return!!e&&"object"==typeof e}function isString(e){return"string"==typeof e||!isArray(e)&&isObjectLike(e)&&objectToString.call(e)==stringTag}function isSymbol(e){return"symbol"==typeof e||isObjectLike(e)&&objectToString.call(e)==symbolTag}function toFinite(e){return e?(e=toNumber(e))===INFINITY||e===-INFINITY?(e<0?-1:1)*MAX_INTEGER:e==e?e:0:0===e?e:0}function toInteger(e){var r=toFinite(e),t=r%1;return r==r?t?r-t:r:0}function toNumber(e){if("number"==typeof e)return e;if(isSymbol(e))return NAN;if(isObject$1(e)){var r="function"==typeof e.valueOf?e.valueOf():e;e=isObject$1(r)?r+"":r}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(reTrim,"");var t=reIsBinary.test(e);return t||reIsOctal.test(e)?freeParseInt(e.slice(2),t?2:8):reIsBadHex.test(e)?NAN:+e}function keys(e){return isArrayLike(e)?arrayLikeKeys(e):baseKeys(e)}function values(e){return e?baseValues(e,keys(e)):[]}var lodash_includes=includes,boolTag="[object Boolean]",objectProto$1=Object.prototype,objectToString$1=objectProto$1.toString;function isBoolean(e){return!0===e||!1===e||isObjectLike$1(e)&&objectToString$1.call(e)==boolTag}function isObjectLike$1(e){return!!e&&"object"==typeof e}var lodash_isboolean=isBoolean,INFINITY$1=1/0,MAX_INTEGER$1=17976931348623157e292,NAN$1=NaN,symbolTag$1="[object Symbol]",reTrim$1=/^\s+|\s+$/g,reIsBadHex$1=/^[-+]0x[0-9a-f]+$/i,reIsBinary$1=/^0b[01]+$/i,reIsOctal$1=/^0o[0-7]+$/i,freeParseInt$1=parseInt,objectProto$2=Object.prototype,objectToString$2=objectProto$2.toString;function isInteger(e){return"number"==typeof e&&e==toInteger$1(e)}function isObject$2(e){var r=typeof e;return!!e&&("object"==r||"function"==r)}function isObjectLike$2(e){return!!e&&"object"==typeof e}function isSymbol$1(e){return"symbol"==typeof e||isObjectLike$2(e)&&objectToString$2.call(e)==symbolTag$1}function toFinite$1(e){return e?(e=toNumber$1(e))===INFINITY$1||e===-INFINITY$1?(e<0?-1:1)*MAX_INTEGER$1:e==e?e:0:0===e?e:0}function toInteger$1(e){var r=toFinite$1(e),t=r%1;return r==r?t?r-t:r:0}function toNumber$1(e){if("number"==typeof e)return e;if(isSymbol$1(e))return NAN$1;if(isObject$2(e)){var r="function"==typeof e.valueOf?e.valueOf():e;e=isObject$2(r)?r+"":r}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(reTrim$1,"");var t=reIsBinary$1.test(e);return t||reIsOctal$1.test(e)?freeParseInt$1(e.slice(2),t?2:8):reIsBadHex$1.test(e)?NAN$1:+e}var lodash_isinteger=isInteger,numberTag="[object Number]",objectProto$3=Object.prototype,objectToString$3=objectProto$3.toString;function isObjectLike$3(e){return!!e&&"object"==typeof e}function isNumber(e){return"number"==typeof e||isObjectLike$3(e)&&objectToString$3.call(e)==numberTag}var lodash_isnumber=isNumber,objectTag="[object Object]";function isHostObject(e){var r=!1;if(null!=e&&"function"!=typeof e.toString)try{r=!!(e+"")}catch(e){}return r}function overArg$1(e,r){return function(t){return e(r(t))}}var funcProto=Function.prototype,objectProto$4=Object.prototype,funcToString=funcProto.toString,hasOwnProperty$1=objectProto$4.hasOwnProperty,objectCtorString=funcToString.call(Object),objectToString$4=objectProto$4.toString,getPrototype=overArg$1(Object.getPrototypeOf,Object);function isObjectLike$4(e){return!!e&&"object"==typeof e}function isPlainObject(e){if(!isObjectLike$4(e)||objectToString$4.call(e)!=objectTag||isHostObject(e))return!1;var r=getPrototype(e);if(null===r)return!0;var t=hasOwnProperty$1.call(r,"constructor")&&r.constructor;return"function"==typeof t&&t instanceof t&&funcToString.call(t)==objectCtorString}var lodash_isplainobject=isPlainObject,stringTag$1="[object String]",objectProto$5=Object.prototype,objectToString$5=objectProto$5.toString,isArray$1=Array.isArray;function isObjectLike$5(e){return!!e&&"object"==typeof e}function isString$1(e){return"string"==typeof e||!isArray$1(e)&&isObjectLike$5(e)&&objectToString$5.call(e)==stringTag$1}var lodash_isstring=isString$1,FUNC_ERROR_TEXT="Expected a function",INFINITY$2=1/0,MAX_INTEGER$2=17976931348623157e292,NAN$2=NaN,symbolTag$2="[object Symbol]",reTrim$2=/^\s+|\s+$/g,reIsBadHex$2=/^[-+]0x[0-9a-f]+$/i,reIsBinary$2=/^0b[01]+$/i,reIsOctal$2=/^0o[0-7]+$/i,freeParseInt$2=parseInt,objectProto$6=Object.prototype,objectToString$6=objectProto$6.toString;function before(e,r){var t;if("function"!=typeof r)throw new TypeError(FUNC_ERROR_TEXT);return e=toInteger$2(e),function(){return--e>0&&(t=r.apply(this,arguments)),e<=1&&(r=void 0),t}}function once(e){return before(2,e)}function isObject$3(e){var r=typeof e;return!!e&&("object"==r||"function"==r)}function isObjectLike$6(e){return!!e&&"object"==typeof e}function isSymbol$2(e){return"symbol"==typeof e||isObjectLike$6(e)&&objectToString$6.call(e)==symbolTag$2}function toFinite$2(e){return e?(e=toNumber$2(e))===INFINITY$2||e===-INFINITY$2?(e<0?-1:1)*MAX_INTEGER$2:e==e?e:0:0===e?e:0}function toInteger$2(e){var r=toFinite$2(e),t=r%1;return r==r?t?r-t:r:0}function toNumber$2(e){if("number"==typeof e)return e;if(isSymbol$2(e))return NAN$2;if(isObject$3(e)){var r="function"==typeof e.valueOf?e.valueOf():e;e=isObject$3(r)?r+"":r}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(reTrim$2,"");var t=reIsBinary$2.test(e);return t||reIsOctal$2.test(e)?freeParseInt$2(e.slice(2),t?2:8):reIsBadHex$2.test(e)?NAN$2:+e}var lodash_once=once,SUPPORTED_ALGS=["RS256","RS384","RS512","ES256","ES384","ES512","HS256","HS384","HS512","none"];psSupported&&SUPPORTED_ALGS.splice(3,0,"PS256","PS384","PS512");var sign_options_schema={expiresIn:{isValid:function(e){return lodash_isinteger(e)||lodash_isstring(e)&&e},message:'"expiresIn" should be a number of seconds or string representing a timespan'},notBefore:{isValid:function(e){return lodash_isinteger(e)||lodash_isstring(e)&&e},message:'"notBefore" should be a number of seconds or string representing a timespan'},audience:{isValid:function(e){return lodash_isstring(e)||Array.isArray(e)},message:'"audience" must be a string or array'},algorithm:{isValid:lodash_includes.bind(null,SUPPORTED_ALGS),message:'"algorithm" must be a valid string enum value'},header:{isValid:lodash_isplainobject,message:'"header" must be an object'},encoding:{isValid:lodash_isstring,message:'"encoding" must be a string'},issuer:{isValid:lodash_isstring,message:'"issuer" must be a string'},subject:{isValid:lodash_isstring,message:'"subject" must be a string'},jwtid:{isValid:lodash_isstring,message:'"jwtid" must be a string'},noTimestamp:{isValid:lodash_isboolean,message:'"noTimestamp" must be a boolean'},keyid:{isValid:lodash_isstring,message:'"keyid" must be a string'},mutatePayload:{isValid:lodash_isboolean,message:'"mutatePayload" must be a boolean'}},registered_claims_schema={iat:{isValid:lodash_isnumber,message:'"iat" should be a number of seconds'},exp:{isValid:lodash_isnumber,message:'"exp" should be a number of seconds'},nbf:{isValid:lodash_isnumber,message:'"nbf" should be a number of seconds'}};function validate(e,r,t,n){if(!lodash_isplainobject(t))throw new Error('Expected "'+n+'" to be a plain object.');Object.keys(t).forEach((function(o){var i=e[o];if(i){if(!i.isValid(t[o]))throw new Error(i.message)}else if(!r)throw new Error('"'+o+'" is not allowed in "'+n+'"')}))}function validateOptions(e){return validate(sign_options_schema,!1,e,"options")}function validatePayload(e){return validate(registered_claims_schema,!0,e,"payload")}var options_to_payload={audience:"aud",issuer:"iss",subject:"sub",jwtid:"jti"},options_for_objects=["expiresIn","notBefore","noTimestamp","audience","issuer","subject","jwtid"],sign$1=function(e,r,t,n){"function"==typeof t?(n=t,t={}):t=t||{};var o="object"==typeof e&&!Buffer.isBuffer(e),i=Object.assign({alg:t.algorithm||"HS256",typ:o?"JWT":void 0,kid:t.keyid},t.header);function s(e){if(n)return n(e);throw e}if(!r&&"none"!==t.algorithm)return s(new Error("secretOrPrivateKey must have a value"));if(void 0===e)return s(new Error("payload is required"));if(o){try{validatePayload(e)}catch(e){return s(e)}t.mutatePayload||(e=Object.assign({},e))}else{var a=options_for_objects.filter((function(e){return void 0!==t[e]}));if(a.length>0)return s(new Error("invalid "+a.join(",")+" option for "+typeof e+" payload"))}if(void 0!==e.exp&&void 0!==t.expiresIn)return s(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));if(void 0!==e.nbf&&void 0!==t.notBefore)return s(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));try{validateOptions(t)}catch(e){return s(e)}var u=e.iat||Math.floor(Date.now()/1e3);if(t.noTimestamp?delete e.iat:o&&(e.iat=u),void 0!==t.notBefore){try{e.nbf=timespan(t.notBefore,u)}catch(e){return s(e)}if(void 0===e.nbf)return s(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}if(void 0!==t.expiresIn&&"object"==typeof e){try{e.exp=timespan(t.expiresIn,u)}catch(e){return s(e)}if(void 0===e.exp)return s(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}Object.keys(options_to_payload).forEach((function(r){var n=options_to_payload[r];if(void 0!==t[r]){if(void 0!==e[n])return s(new Error('Bad "options.'+r+'" option. The payload already has an "'+n+'" property.'));e[n]=t[r]}}));var c=t.encoding||"utf8";if("function"!=typeof n)return jws.sign({header:i,payload:e,secret:r,encoding:c});n=n&&lodash_once(n),jws.createSign({header:i,privateKey:r,payload:e,encoding:c}).once("error",n).once("done",(function(e){n(null,e)}))},jsonwebtoken={decode:decode$1,verify:verify$1,sign:sign$1,JsonWebTokenError:JsonWebTokenError_1,NotBeforeError:NotBeforeError_1,TokenExpiredError:TokenExpiredError_1},src=jsonwebtoken;module.exports=src;
......@@ -12,6 +12,6 @@
"path": "/uni-pay-co",
"timeout": 60,
"triggers": [],
"runtime": "Nodejs8"
"runtime": "Nodejs18"
}
}
\ No newline at end of file
}
......@@ -32,7 +32,7 @@ class service {
getConfig() {
return config;
}
/**
* 支付成功 - 异步通知
*/
......@@ -157,7 +157,7 @@ class service {
return libs.common.returnNotifySUCCESS({ provider, provider_pay_type });
}
/**
* 微信虚拟支付异步通知
*/
......@@ -187,6 +187,7 @@ class service {
clientInfo, // 客户端信息
cloudInfo, // 云端信息
wxpay_virtual, // 仅用于微信虚拟支付
apple_virtual, // 仅用于苹果虚拟支付
} = data;
let subject = description;
let body = description;
......@@ -204,6 +205,13 @@ class service {
if (typeof wxpay_virtual.buy_quantity !== "number" || wxpay_virtual.buy_quantity <= 0) {
throw { errCode: ERROR[51012] };
}
} else if (provider === "appleiap") {
if (typeof apple_virtual !== "object") {
throw { errCode: ERROR[51013] };
}
if (typeof apple_virtual.buy_quantity !== "number" || apple_virtual.buy_quantity <= 0) {
throw { errCode: ERROR[51012] };
}
} else {
if (typeof total_fee !== "number" || total_fee <= 0 || total_fee % 1 !== 0) {
throw { errCode: ERROR[51005] };
......@@ -319,7 +327,7 @@ class service {
// 微信虚拟支付扩展数据
expand_data = {
mode: wxpay_virtual.mode, // short_series_coin 代币充值; short_series_goods 道具直购
buy_quantity: wxpay_virtual.buy_quantity,
buy_quantity: wxpay_virtual.buy_quantity,
rate: uniPayConifg.rate || 100,
sandbox: uniPayConifg.sandbox,
};
......@@ -344,7 +352,7 @@ class service {
} else if (getOrderInfoParam.mode === "short_series_goods") {
// 计算支付金额
total_fee = expand_data.buy_quantity * expand_data.goods_price;
}
}
}
orderInfo = await uniPayInstance.getOrderInfo(getOrderInfoParam);
if (qr_code && orderInfo.codeUrl) {
......@@ -397,6 +405,11 @@ class service {
let userInfo = await dao.uniIdUsers.findById(user_id);
if (userInfo) nickname = userInfo.nickname;
}
let appleiap_account_token;
if (provider === "appleiap") {
appleiap_account_token = libs.crypto.generateUUID();
res.appleiap_account_token = appleiap_account_token;
}
await dao.uniPayOrders.add({
provider,
provider_pay_type,
......@@ -419,6 +432,7 @@ class service {
custom,
create_date,
expand_data,
appleiap_account_token, // 苹果虚拟支付专用字段
stat_data: {
platform: stat_platform,
app_version: clientInfo.appVersion,
......@@ -466,7 +480,7 @@ class service {
payOrderInfo = await dao.uniPayOrders.find({
out_trade_no
});
}
}
if (!payOrderInfo) {
throw { errCode: ERROR[52001] };
}
......@@ -487,7 +501,7 @@ class service {
console.log('queryRes: ', queryRes)
} else {
// 无uniPayInstance.orderQuery函数时的兼容处理
if ([1,2].indexOf(payOrderInfo.status) > -1) {
if ([1, 2].indexOf(payOrderInfo.status) > -1) {
queryRes = {
tradeState: "SUCCESS",
tradeStateDesc: "订单已支付"
......@@ -610,7 +624,7 @@ class service {
if (errMsg) {
if (errMsg.indexOf("verify failure") > -1) {
throw { errCode: ERROR[53005] };
}
}
if (errMsg.indexOf("header too long") > -1) {
throw { errCode: ERROR[53005] };
}
......@@ -754,7 +768,7 @@ class service {
});
let wxpayResult = (provider === "wxpay" && closeOrderRes.resultCode === "SUCCESS");
let alipayResult = (provider === "alipay" && closeOrderRes.code === "10000");
if (wxpayResult || alipayResult) {
// 修改订单状态为已取消
await dao.uniPayOrders.update({
......@@ -806,8 +820,8 @@ class service {
uniPayConifg = wxpayVirtualPayConifg;
needCacheSessionKey = true;
}
} catch(err){}
} catch (err) {}
let res = await libs.wxpay.getOpenid({
config: uniPayConifg,
code,
......@@ -860,62 +874,207 @@ class service {
async verifyReceiptFromAppleiap(data) {
let {
out_trade_no,
appleiap_account_token,
transaction_receipt,
transaction_identifier,
clientInfo,
} = data;
if (!out_trade_no) {
throw { errCode: ERROR[51001] };
if (!appleiap_account_token) {
return {
errCode: 0,
errMsg: "Invalid out_trade_no"
}
}
appleiap_account_token = appleiap_account_token.toLowerCase(); // 转小写
let payOrderInfo = await dao.uniPayOrders.find({
provider: "appleiap",
appleiap_account_token
});
if (!payOrderInfo || !payOrderInfo.out_trade_no) {
return {
errCode: 0,
errMsg: "Invalid out_trade_no"
}
}
out_trade_no = payOrderInfo.out_trade_no;
}
// 初始化uniPayInstance
let uniPayInstance = await this.initUniPayInstance({ provider: "appleiap", provider_pay_type: "app" });
let verifyReceiptRes = await uniPayInstance.verifyReceipt({
receiptData: transaction_receipt
let payOrderInfo = await dao.uniPayOrders.find({
out_trade_no,
});
if (!payOrderInfo) {
throw { errCode: ERROR[52001] };
}
const verifyReceipt = async (uniPayConifg) => {
const jwt = libs.jsonwebtoken;
const fs = require('fs');
const privateKey = fs.readFileSync(uniPayConifg.appCertPath, 'utf8');
const header = {
alg: 'ES256',
kid: uniPayConifg.appId, // 替换为您的密钥ID
typ: "JWT"
};
const nowTime = Date.now();
const bundleId = uniPayConifg.sandbox ? uniPayConifg.devBundleId || uniPayConifg.bundleId : uniPayConifg.bundleId;
const payload = {
iss: uniPayConifg.issuerId, // 替换为您的团队ID
iat: Math.floor(nowTime / 1000), // 当前时间戳
exp: Math.floor(nowTime / 1000) + 3600, // 当前时间戳加1小时
aud: 'appstoreconnect-v1',
bid: bundleId
};
const iapToken = jwt.sign(payload, privateKey, {
algorithm: 'ES256',
header: header
});
const serviceUrl = uniPayConifg.sandbox ? "https://api.storekit-sandbox.itunes.apple.com" : "https://api.appstoreconnect.apple.com";
const url = `${serviceUrl}/inApps/v1/transactions/${transaction_identifier}`;
let requestRes;
// 如果请求苹果服务器失败,则重试5次
for (let i = 0; i <= 5; i++) {
try {
requestRes = await uniCloud.request({
method: "GET",
header: {
'Authorization': `Bearer ${iapToken}`,
'Content-Type': 'application/json'
},
url
});
break;
} catch (err) {
// console.log('errCode: ', err.code || err.errCode, 'errMsg: ', err.message || err.errMsg)
}
}
if (requestRes.statusCode !== 200) {
return {};
}
const signedInfoTokenArr = requestRes.data.signedTransactionInfo.split('.');
const signedInfoString = Buffer.from(signedInfoTokenArr[1], 'base64').toString('utf8');
const verifyReceiptRes = JSON.parse(signedInfoString);
const appAccountToken = verifyReceiptRes.appAccountToken.toLowerCase();
verifyReceiptRes.tradeState = verifyReceiptRes.inAppOwnershipType === "PURCHASED" && payOrderInfo.appleiap_account_token === appAccountToken ? "SUCCESS" : "fail";
return verifyReceiptRes;
};
let uniPayConifg = await this.getUniPayConfig({ provider: "appleiap", provider_pay_type: "app" });
let verifyReceiptRes = await verifyReceipt(uniPayConifg);
let userOrderSuccess = false;
let pay_date;
if (verifyReceiptRes.tradeState !== "SUCCESS") {
throw { errCode: ERROR[54002] };
// 尝试使用相反的环境再次验证
console.log('尝试使用相反的环境再次验证: ');
verifyReceiptRes = await verifyReceipt({
...uniPayConifg,
sandbox: !uniPayConifg.sandbox
});
if (verifyReceiptRes.tradeState !== "SUCCESS") {
// 如果还是不成功,则校验不通过
throw { errCode: ERROR[54002] };
}
}
// 支付成功
pay_date = Number(verifyReceiptRes.receipt.receipt_creation_date_ms);
let inAppList = verifyReceiptRes.receipt.in_app;
let inApp = inAppList.find((item) => {
return item.transaction_id === transaction_identifier;
});
if (!inApp) {
// 校验不通过
throw { errCode: ERROR[54002] };
//console.log('verifyReceiptRes: ', verifyReceiptRes)
let isSubscribe = false;
if (["Auto-Renewable Subscription"].indexOf(verifyReceiptRes.type) > -1) {
isSubscribe = true; // 标记为自动订阅订单
}
let quantity = inApp.quantity; // 购买数量
let product_id = inApp.product_id; // 对应的内购产品id
let transaction_id = inApp.transaction_id; // 本次交易id
if ((Date.now() - 1000 * 3600 * 24) > pay_date) {
// 订单已超24小时,不做处理,通知前端直接关闭订单。
// 支付成功
pay_date = Number(verifyReceiptRes.purchaseDate);
let quantity = verifyReceiptRes.quantity; // 购买数量
let product_id = verifyReceiptRes.productId; // 对应的内购产品id
let transaction_id = verifyReceiptRes.transactionId; // 本次交易id
let original_transaction_id = verifyReceiptRes.originalTransactionId; // 原始交易id
if ((Date.now() - 1000 * 3600 * 72) > pay_date && !isSubscribe) {
// 非自动订阅订单,若超72小时,不做处理,通知前端直接关闭订单。
return {
errCode: 0,
errMsg: "ok"
};
}
if (isSubscribe && original_transaction_id !== transaction_id) {
let findOrderInfo = await dao.uniPayOrders.find({
appleiap_account_token: payOrderInfo.appleiap_account_token,
user_order_success: _.exists(true)
});
if (findOrderInfo) {
// 自动订阅产品自动续期时需要创建新的支付订单
let quantity = verifyReceiptRes.quantity;
let goods_price = parseFloat((verifyReceiptRes.price / 1000).toFixed(2));
let total_fee = parseFloat((goods_price * 100 * quantity).toFixed(2));
let description = "[自动续期]" + payOrderInfo.description.replace(/\[自动续期\]/g, '');
// 添加数据库(数据库的out_trade_no字段需设置为唯一索引)
let stat_platform = clientInfo.platform;
if (stat_platform === "app") {
stat_platform = clientInfo.os;
}
// 创建新的支付订单
let addId = await dao.uniPayOrders.add({
provider: payOrderInfo.provider,
provider_pay_type: payOrderInfo.provider_pay_type,
uni_platform: clientInfo.platform,
status: 0,
type: payOrderInfo.type,
order_no: payOrderInfo.order_no,
out_trade_no: transaction_id,
user_id: payOrderInfo.user_id,
nickname: payOrderInfo.nickname,
device_id: clientInfo.deviceId,
client_ip: clientInfo.client_ip,
openid: payOrderInfo.openid,
description,
total_fee,
refund_fee: 0,
refund_count: 0,
provider_appid: uniPayConifg.appId,
appid: clientInfo.appId,
custom: payOrderInfo.custom,
create_date: Date.now(),
expand_data: payOrderInfo.expand_data,
appleiap_account_token, // 苹果虚拟支付专用字段
stat_data: {
platform: stat_platform,
app_version: clientInfo.appVersion,
app_version_code: clientInfo.appVersionCode,
app_wgt_version: clientInfo.appWgtVersion,
os: clientInfo.os,
ua: clientInfo.ua,
channel: clientInfo.channel ? clientInfo.channel : String(clientInfo.scene),
scene: clientInfo.scene
}
});
payOrderInfo = await dao.uniPayOrders.find({
_id: addId,
});
out_trade_no = transaction_id;
}
}
// 查询该transaction_id是否使用过,如果已使用,则不做处理,通知前端直接关闭订单。
let findOrderInfo = await dao.uniPayOrders.find({
transaction_id,
});
if (findOrderInfo) {
const repeatReceipt = () => {
return {
errCode: 0,
errMsg: "ok"
errMsg: "ok",
repeat: true, // 代表重复通知了
};
};
if (findOrderInfo) {
// 不允许重复通知
return repeatReceipt();
}
// 否则,执行用户回调
// 用户自己的逻辑处理 开始-----------------------------------------------------------
let orderPaySuccess;
let payOrderInfo = await dao.uniPayOrders.find({
out_trade_no,
});
if (!payOrderInfo) {
throw { errCode: ERROR[52001] };
}
try {
// 加载自定义异步回调函数
orderPaySuccess = require(`../notify/${payOrderInfo.type}`);
......@@ -923,7 +1082,7 @@ class service {
console.log(err);
}
if (typeof orderPaySuccess === "function") {
payOrderInfo = await dao.uniPayOrders.updateAndReturn({
let newPayOrderInfo = await dao.uniPayOrders.updateAndReturn({
whereJson: {
status: 0, // status:0 为必须条件,防止重复推送时的错误
out_trade_no: out_trade_no, // 商户订单号
......@@ -936,6 +1095,11 @@ class service {
original_data: verifyReceiptRes
}
});
if (!newPayOrderInfo) {
// 不允许重复通知
return repeatReceipt();
}
payOrderInfo = newPayOrderInfo;
console.log('用户自己的回调逻辑 - 开始执行');
userOrderSuccess = await orderPaySuccess({
verifyResult: verifyReceiptRes,
......@@ -969,9 +1133,10 @@ class service {
status: payOrderInfo.status, // 标记当前支付订单状态 -1:已关闭 0:未支付 1:已支付 2:已部分退款 3:已全额退款
user_order_success: payOrderInfo.user_order_success, // 用户异步通知逻辑是否全部执行完成,且无异常(建议前端通过此参数是否为true来判断是否支付成功)
pay_order: payOrderInfo,
is_subscribe: isSubscribe
};
}
/**
* 获取对应支付配置
* let uniPayConifg = await this.getUniPayConfig({ provider, provider_pay_type });
......@@ -1007,7 +1172,7 @@ class service {
if (uniPayConifg.version === 3) {
try {
uniPayInstance = uniPay.initWeixinV3(uniPayConifg);
} catch(err){
} catch (err) {
console.error(err);
let errMsg = err.message;
if (errMsg && errMsg.indexOf("invalid base64 body") > -1) {
......@@ -1022,28 +1187,12 @@ class service {
// 支付宝
uniPayInstance = uniPay.initAlipay(uniPayConifg);
} else if (provider === "appleiap") {
// ios内购
// 苹果虚拟支付
uniPayInstance = uniPay.initAppleIapPayment(uniPayConifg);
} else if (provider === "wxpay-virtual") {
// 微信虚拟支付
// 还需要额外传accessToken
let cacheKey = {
appId: uniPayConifg.appId,
platform: "weixin-mp"
}
let cacheInfo = await dao.opendbOpenData.getAccessToken(cacheKey);
if (cacheInfo) {
// 缓存有值
uniPayConifg.accessToken = cacheInfo.access_token;
} else {
// 缓存无值
let getAccessTokenRes = await libs.wxpay.getAccessToken(uniPayConifg);
uniPayConifg.accessToken = getAccessTokenRes.accessToken;
// 缓存accessToken
await dao.opendbOpenData.setAccessToken(cacheKey, {
access_token: getAccessTokenRes.accessToken,
}, getAccessTokenRes.expiresIn);
}
uniPayConifg.accessToken = await this.getAccessToken(data);
uniPayInstance = uniPay.initWeixinVirtualPayment(uniPayConifg);
} else {
throw new Error(`${provider} : 不支持的支付方式`);
......@@ -1051,7 +1200,77 @@ class service {
return uniPayInstance;
}
/**
* 获取accessToken
* let uniPayInstance = await service.pay.getAccessToken({ provider, provider_pay_type });
*/
async getAccessToken(data = {}) {
let uniPayConifg = await this.getUniPayConfig(data);
let cacheKey = {
appId: uniPayConifg.appId,
platform: "weixin-mp"
}
let cacheInfo = await dao.opendbOpenData.getAccessToken(cacheKey);
if (cacheInfo) {
// 缓存有值
return cacheInfo.access_token;
} else {
// 缓存无值
let getAccessTokenRes = await libs.wxpay.getAccessToken(uniPayConifg);
let accessToken = getAccessTokenRes.accessToken;
// 缓存accessToken
await dao.opendbOpenData.setAccessToken(cacheKey, {
access_token: getAccessTokenRes.accessToken,
}, getAccessTokenRes.expiresIn);
return accessToken;
}
}
/**
* 获取sessionKey
* let sessionKey = await service.pay.getSessionKey({ provider, provider_pay_type, openid });
*/
async getSessionKey(data = {}) {
let {
openid,
} = data;
// 获取用户的sessionKey
let uniPayConifg = await this.getUniPayConfig(data);
let { session_key } = await dao.opendbOpenData.getSessionKey({
appId: uniPayConifg.appId,
platform: "weixin-mp",
openid
});
return session_key;
}
/**
* 请求微信小程序虚拟支付API
* let res = await service.pay.requestWxpayVirtualApi(data);
*/
async requestWxpayVirtualApi(options = {}) {
let {
method,
data = {}
} = options;
// 微信虚拟支付固定参数
let provider = "wxpay-virtual";
let provider_pay_type = "mp";
// 获得微信小程序虚拟支付实例
let uniPayInstance = await this.initUniPayInstance({ provider, provider_pay_type });
// 调用微信小程序虚拟支付云端API
if (["currencyPay"].indexOf(method) > -1) {
if (!data.sessionKey) {
data.sessionKey = await this.getSessionKey({ ...data, provider, provider_pay_type });
}
}
let res = await uniPayInstance[method](data);
return res;
}
}
module.exports = new service();
module.exports = new service();
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册