import cloud from '@lafjs/cloud' import { createHash } from 'crypto'; const db = cloud.database(); import crypto from 'crypto'; const mchid = "1719895437";//商户id const serialNo = "2A97ED6ED441E55600EBC8830B9EC889ED41496E";//证书序列号 const ThinkingData = require('thinkingdata-node'); import Ip2region from 'ip2region'; const query = new Ip2region(); const canIos=false; const version="1.9.67"; export default async function (ctx: FunctionContext) { let code = ctx.body.code; let distinctId=ctx.body.distinctId; let isDebug=ctx.body.isDebug; let dbname = "users"; const gameName = ctx.body.gameName; if (gameName == "iaa") { dbname = "usersAd"; } let idname = "687a0e79c03536d5ff982f77"; if (gameName == "iaa") { idname = "68e90168b30b6944c56bdb74"; } let info = await getWXOpenId(code,dbname); if(!info){ return; } let openid = info[0]; let session_key = info[1]; let userData = await getUserData(dbname, openid); let token =await stringToHash(Date.now()+openid); if (!userData) { let ref = await db.collection("idcount").field({ count: 1 }).where({ _id:idname}).getOne(); await db.collection("idcount").where({ _id:idname }).update({ count: ref.data.count + 1 }); await db.collection(dbname).add({ openid: openid, session_key: session_key, register_time: Date.now(), onlyId: ref.data.count, distinctId: distinctId, isDebug: isDebug, levelAmount: 0, coinAmount: 0, healthAmount: 5, healthtimestamp: 0, freezeAmount: 3, hammerAmount: 3, magicAmount: 3, userPowerTime: 0, monthCardReward: 0, monthCardTime: 0, rebornGiftCount: 0, rebornGiftTime: 0, useravatar: Math.floor(Math.random() * 4) + "", username:"user", pay_user: false, isWhite: false, isFirst: true, starter_pack: 0, starter_packState: 0, careerAmount:0, useravatarIcon: "0", forcedUpdate:false, token:token }); } else { let taskTime = userData.taskTime || 0; let task = userData.task; if (task) { task = JSON.parse(task); } else { task = { levelPass: { value: 0, state: 0, }, share: { value: 0, state: 0, }, useEnergy: { value: 0, state: 0, }, useProp: { value: 0, state: 0, } } } const now = new Date(Date.now() + 8 * 3600000); now.setHours(0, 0, 0, 0); // 直接修改当前Date对象 const timestamp = now.getTime(); if (timestamp > taskTime) { for (var key in task) { task[key].value = 0; task[key].state = 0; } } await db.collection(dbname).where({ _id: userData._id }).update({ session_key: session_key, distinctId: distinctId, isDebug: isDebug, isFirst: false, task: JSON.stringify(task), taskTime: Date.now() + 8 * 3600000,token:token }); } if(userData?.freeze){ return {code:0,data:"数据有误,无法进入游戏",msg:"数据有误,无法进入游戏"}; } await delayExecution(0.1); userData = await getUserData(dbname, openid); let res= null; if (userData.openid) { res = await db.collection("order").where({ state: 1, openid: userData.openid }).get(); } let outTradeNo:any=[]; if(res.data&&res.data.length>0){ for(let i=0;i { return ( req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP req.headers['x-real-ip'] || // Nginx 配置的 real-ip req.socket.remoteAddress // 原始 IP(可能是代理) ); }; const propName = { "金币包1": "gold_1", "金币包2": "gold_2", "金币包3": "gold_3", "金币包4": "gold_4", "金币包5": "gold_5", "金币包6": "gold_6", "无限体力组合包1": "unlimited_health_bundle_1", "无限体力组合包2": "unlimited_health_bundle_2", "无限体力组合包3": "unlimited_health_bundle_3", "局内购买冻结": "freeze_in_game", "局内购买锤子": "hammer_in_game", "局内购买魔棒": "wand_in_gamerefill", "补满体力": "health" }; function getTodayStartTimestamp() { const date = new Date(); date.setHours(0, 0, 0, 0); return date.getTime(); } async function getWXOpenId(code,dbname) { let appid = "wxdd145ced49158a1e"; let appsecret = "7f295245ffc4884b03306c64e30654db"; if (dbname =="usersAd"){ appid = "wxe69a671ea2c93af3"; appsecret ="1eef42cd8810024eaea6dac961f9b3b0"; } const api_url = `https://api.weixin.qq.com/sns/jscode2session`; const param = `appid=${appid}&secret=${appsecret}&js_code=${code}&grant_type=authorization_code`; let res = null; try { res = await cloud.fetch(`${api_url}?${param}`, { headers: { "Accept-Encoding": 'gzip' } }); } catch { } if (res == null || res.data.errcode > 0) { return null } //console.log(res.data); return [res?.data?.openid, res?.data?.session_key] } /**获取当前用户数据 */ async function getUserData(dbname: string, openid: any, isFirst?) { let { data } = await db.collection(dbname).where({ openid: openid }).get(); if (data.length) { return data[0]; } return null; } async function delayExecution(seconds: number) { return new Promise((resolve) => { setTimeout(() => { // 在这里编写需要延时执行的代码 resolve("延时执行完成"); }, seconds * 1000); }); } async function getIosOrder(openid,ctx){ let res = await db.collection("order").where({state: 0,type:"ios",openid:openid}).get(); let res1 = await db.collection("users").where({ openid: openid }).getOne(); let list=[]; if(res.data.length>0){ for(let i=0;i3*3600000){ let ret = await db.collection('order').where({ outTradeNo: res.data[i].outTradeNo}).remove({ multi: true }); } } } } return list; } async function sead(order, userInfo, ip) { if (!userInfo.distinctId) { return; } let id = '87d18958cea145f29d3265470ecd3486'; if (userInfo.isDebug != "true") { id = '121591378fc1423893deb12041413eb3'; } let teSDK = ThinkingData.initWithBatchMode(id, 'https://data.nika4fun.com/sync_data', { dryRun: false, // report data to TE or not deviceId: "123456789",//设备唯一标识 }); let trackEvent = { accountId: order.openid, distinctId: userInfo.distinctId,//访客id event: 'payment', time: new Date(Date.now() + 8 * 3600000), ip: ip, properties: { order_id: order.outTradeNo, pay_amount: order.goodsPrice, payment_name: order.itemid, payment_num: order.itemCount, payment_type: "ios", current_level: userInfo.lv, //当前关卡等级 number current_health: userInfo.healthAmount, //当前体力值 tmp_coin: userInfo.coinAmount,//当前金币 version: "1.6", user_id: userInfo._id, //用户id pay_user: userInfo.pay_user }, callback(e) { if (e) { console.log(e); } } }; teSDK.track(trackEvent); teSDK.close(); return; } /**获取订单*/ async function getOrder(outTradeNo) { const url = `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437`; const nonceStr = crypto.randomBytes(16).toString('hex'); const timestamp = Math.floor(Date.now() / 1000).toString(); let au = await sign(outTradeNo, nonceStr, timestamp); let res = await fetch(url, { method: 'GET', // 默认是 GET,可省略 headers: { 'Authorization': au, // 认证令牌 'Content-Type': 'application/json', // 声明请求体类型(GET 请求通常不需要) 'Accept': 'application/json', // 声明期望的响应类型 } }) const data = await res.json(); return data; } async function sign(outTradeNo, nonceStr, timestamp) { const data = `GET\n/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437\n${timestamp}\n${nonceStr}\n\n` // 创建签名对象 const sign = crypto.createSign('RSA-SHA256'); // 更新签名内容 sign.update(data); // 获取存储桶 const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss'); // 获取文件列表 const res = await bucket.readFile('apiclient_key.pem'); const privateKeyPem = await res.Body.transformToString(); // 使用私钥签名(PKCS1 填充) const signature = sign.sign({ key: privateKeyPem, padding: crypto.constants.RSA_PKCS1_PADDING }, 'base64'); // 构建Authorization头 const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timestamp}",serial_no="${serialNo}"`; return authorization; } /** * 根据 IP 获取省份名称 * @param {string} ip - 用户 IP 地址 * @returns {string} 省份名称(如 "广东省"),未知时返回 "未知" */ function getProvinceByIP(ip) { try { const result = query.search(ip); //console.log(result); if (!result || !result.country.includes('中国')) { return '其他'; } // ip2region 返回的格式示例:"中国|0|广东省|深圳市|电信" const parts = result.province; const provinceCode = parts[2]; // 省份代码在第三部分 // 检查是否是已知的省份代码 // if (PROVCE_CODE_MAP[provinceCode]) { // return PROVINCE_CODE_MAP[provinceCode]; // } // 如果未映射,返回原始代码(可能是数据库更新后的新代码) return parts || '其他'; } catch (error) { console.error('IP 解析失败:', error); return '其他'; } }