From cf3ac60e915060dd9a0cb4c3fa3b6f0d0175ac8c Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Wed, 19 Jul 2023 19:04:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=B8=AA=E4=BE=9B?= =?UTF-8?q?=E6=B8=B8=E6=88=8F=E6=9C=8D=E4=BA=8C=E6=AC=A1=E7=A1=AE=E8=AE=A4?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/internal.controller.ts | 24 ++++++++++++++++++++++++ src/service/game.svr.ts | 26 ++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/controllers/internal.controller.ts b/src/controllers/internal.controller.ts index d96fde4..29cd8be 100644 --- a/src/controllers/internal.controller.ts +++ b/src/controllers/internal.controller.ts @@ -8,6 +8,7 @@ import { hmacsha256 } from 'utils/security.util' import { DocumentType } from '@typegoose/typegoose' import { updateOrderStatus } from 'service/alchemy.svr' import { PriceSvr } from 'service/price.svr' +import { assembleGameData, checkGameSign } from 'service/game.svr' const calcHash = function (data: any) { let signStr = JSON.stringify(data) @@ -88,4 +89,27 @@ export default class InternalController extends BaseController { }) return {} } + /** + * 供Game端二次确认支付结果 + */ + @role(ROLE_ANON) + @router('get /api/internal/alchemy/order/:id') + async queryAlchemyPayOrder(req) { + let { id, timestamp, sign } = req.params + if (!id || !timestamp || !sign) { + throw new ZError(10, 'params mismatch') + } + if (timestamp < Date.now() / 1000 - 60 * 5) { + throw new ZError(11, 'timestamp expired') + } + if (!checkGameSign({ id, timestamp, sign })) { + throw new ZError(12, 'sign not match') + } + let record = await PayRecord.findById(id) + if (!record) { + throw new ZError(13, 'PayRecord not found') + } + const repData = assembleGameData(record) + return repData + } } diff --git a/src/service/game.svr.ts b/src/service/game.svr.ts index b46354b..26da40e 100644 --- a/src/service/game.svr.ts +++ b/src/service/game.svr.ts @@ -12,14 +12,24 @@ export interface IPayResult { status: number } -export async function reportPayResult(data: DocumentType) { - const repData = { +export function assembleGameData(data: DocumentType) { + return { account_id: data.gameAccountId, order_id: data.gameOrderId, status: data.status, id: data.id, txhash: data.txHash, } +} + +export function checkGameSign({ id, timestamp, sign }: { id: string; timestamp: string; sign: string }) { + const signStr = `id=${id}×tamp=${timestamp}` + const hash = hmacsha256(signStr, process.env.HASH_SALT) + return sign === hash +} + +export async function reportPayResult(data: DocumentType) { + const repData = assembleGameData(data) const signStr = Object.keys(repData) .sort() .map(key => `${key}=${encodeURIComponent(repData[key])}`) @@ -37,12 +47,20 @@ export async function reportPayResult(data: DocumentType) { } // 上报google支付结果 export async function reportGooglePurchaseResult(records: IPayResult[]) { + return reportPurchaseResult(records, 'google') +} + +export async function reportApplePurchaseResult(records: IPayResult[]) { + return reportPurchaseResult(records, 'apple') +} + +export async function reportPurchaseResult(records: IPayResult[], channel: string) { const url = `${process.env.GAME_PAY_CB_URL}?c=Shop&a=inappPurchaseDiamonds` let reportData: any = { - channel: 'google', + channel, records, } - let signStr = 'channel=google&' + let signStr = `channel=${channel}&` signStr += records .map(record => Object.keys(record)