|
|
@@ -22,7 +22,8 @@ import { LessThan, MoreThan, Not, Repository } from 'typeorm'
|
|
|
import { addSeconds } from 'date-fns'
|
|
|
import * as fs from 'node:fs'
|
|
|
import { JsapiTicketCache } from './entities/jsapi-ticket-cache.entity'
|
|
|
-import { WeixinNotifyDto } from './dto/notify.dto'
|
|
|
+import { Attach } from './dto/attach.dto'
|
|
|
+import { v4 as uuid } from 'uuid'
|
|
|
|
|
|
@Injectable()
|
|
|
export class WeixinService {
|
|
|
@@ -85,12 +86,8 @@ export class WeixinService {
|
|
|
return res
|
|
|
}
|
|
|
|
|
|
- getRedirectUrl() {
|
|
|
- return SnsAccessTokenApi.getAuthorizeUrl(
|
|
|
- 'https://chillgpt.raexmeta.com/ui/#/home',
|
|
|
- ScopeEnum.SNSAPI_BASE,
|
|
|
- 'pay'
|
|
|
- )
|
|
|
+ getRedirectUrl(url: string, state?: string) {
|
|
|
+ return SnsAccessTokenApi.getAuthorizeUrl(url, ScopeEnum.SNSAPI_BASE, state)
|
|
|
}
|
|
|
|
|
|
async code2oenId(code: string) {
|
|
|
@@ -151,6 +148,53 @@ export class WeixinService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ async jsapiPay(description: string, amount: number, openid: string, attach: Attach) {
|
|
|
+ let data = {
|
|
|
+ appid: this.weixinConfiguration.appId,
|
|
|
+ mchid: this.weixinConfiguration.mchId,
|
|
|
+ description: description,
|
|
|
+ out_trade_no: uuid(),
|
|
|
+ notify_url: this.weixinConfiguration.notifyUrl,
|
|
|
+ amount: {
|
|
|
+ total: amount * 100,
|
|
|
+ currency: 'CNY'
|
|
|
+ },
|
|
|
+ payer: {
|
|
|
+ openid
|
|
|
+ },
|
|
|
+ attach: JSON.stringify(attach)
|
|
|
+ }
|
|
|
+ let result = await PayKit.exePost(
|
|
|
+ WX_DOMAIN.CHINA, //
|
|
|
+ WX_API_TYPE.JS_API_PAY,
|
|
|
+ this.weixinConfiguration.mchId,
|
|
|
+ this.weixinConfiguration.certSerial,
|
|
|
+ this.privateKey,
|
|
|
+ JSON.stringify(data)
|
|
|
+ )
|
|
|
+ Logger.log(JSON.stringify(result.data, null, 2), 'jsapi下单')
|
|
|
+ if (result.status === 200) {
|
|
|
+ const timeStamp = parseInt((new Date().getTime() / 1000).toString()).toString()
|
|
|
+ const nonceStr = Kits.generateStr()
|
|
|
+ const packageStr = `prepay_id=${result.data.prepay_id}`
|
|
|
+ const signType = 'RSA'
|
|
|
+ const signStr =
|
|
|
+ [this.weixinConfiguration.appId, timeStamp, nonceStr, packageStr].join(String.fromCharCode(10)) +
|
|
|
+ String.fromCharCode(10)
|
|
|
+ const paySign = Kits.sha256WithRsa(signStr, this.privateKey)
|
|
|
+ return {
|
|
|
+ appId: this.weixinConfiguration.appId,
|
|
|
+ timestamp: timeStamp,
|
|
|
+ nonceStr,
|
|
|
+ package: packageStr,
|
|
|
+ signType,
|
|
|
+ paySign
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new InternalServerErrorException(result.data.message)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
async getCert() {
|
|
|
try {
|
|
|
let result = await PayKit.exeGet(
|
|
|
@@ -206,17 +250,23 @@ export class WeixinService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async notify(headers, data: WeixinNotifyDto) {
|
|
|
+ async getNotifyData(headers, data: WechatPay.NotifyEvent) {
|
|
|
Logger.log(JSON.stringify(headers, null, 2), '微信回调Header')
|
|
|
Logger.log(JSON.stringify(data, null, 2), '微信回调Body')
|
|
|
let verifySignature: boolean = PayKit.verifySign(headers, JSON.stringify(data), this.platformPlublicKey)
|
|
|
Logger.log(verifySignature, '验证签名')
|
|
|
- let decrypt = PayKit.aes256gcmDecrypt(
|
|
|
- this.weixinConfiguration.mchKey,
|
|
|
- data.resource.nonce,
|
|
|
- data.resource.associated_data,
|
|
|
- data.resource.ciphertext
|
|
|
+ if (!verifySignature) {
|
|
|
+ throw new InternalServerErrorException('签名验证失败')
|
|
|
+ }
|
|
|
+ let notifyData: WechatPay.NotifyData = JSON.parse(
|
|
|
+ PayKit.aes256gcmDecrypt(
|
|
|
+ this.weixinConfiguration.mchKey,
|
|
|
+ data.resource.nonce,
|
|
|
+ data.resource.associated_data,
|
|
|
+ data.resource.ciphertext
|
|
|
+ )
|
|
|
)
|
|
|
- Logger.log(decrypt, '解密数据')
|
|
|
+ Logger.log(JSON.stringify(notifyData, null, 2), '解密数据')
|
|
|
+ return notifyData
|
|
|
}
|
|
|
}
|