From 50011f1eaf758c9d94a88a03f581e47acfa97752 Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:46:37 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E5=88=86=E6=8E=A5=E5=8F=A3=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0google=20recaptcha?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/Constants.ts | 3 +++ src/controllers/activity.controller.ts | 2 ++ src/controllers/chest.controller.ts | 2 ++ src/services/discord.svr.ts | 7 +++++++ src/services/google.svr.ts | 27 ++++++++++++++++++++++++++ 5 files changed, 41 insertions(+) create mode 100644 src/services/google.svr.ts diff --git a/src/common/Constants.ts b/src/common/Constants.ts index c86a77e..3f0e4ed 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -46,3 +46,6 @@ export const SCORE_GAME_STEP = 'game_step' export const SCORE_SOCIAL_TASK = 'Social Tasks' // 积分类型-邀请用户额外收益 export const SCORE_INVITE_REBATE = 'invite_rebate' + +// google reCaptcha最小分数 +export const RECAPTCHA_MIN_SCORE = 0.5 diff --git a/src/controllers/activity.controller.ts b/src/controllers/activity.controller.ts index edd6345..76931d3 100644 --- a/src/controllers/activity.controller.ts +++ b/src/controllers/activity.controller.ts @@ -5,6 +5,7 @@ import { BaseController, ROLE_ANON, SyncLocker, ZError, ZRedisClient, role, rout import { ScoreRecord } from 'models/ScoreRecord' import { formatAddress } from 'zutils/utils/chain.util' import { isValidShareCode } from 'common/Utils' +import { checkReCaptcha } from 'services/google.svr' const MAX_LIMIT = 100 export default class ActivityController extends BaseController { @@ -30,6 +31,7 @@ export default class ActivityController extends BaseController { @router('post /api/activity/upload_invite_code') async uploadInviteCode(req) { new SyncLocker().checkLock(req) + await checkReCaptcha(req, 'invite_user') let { code } = req.params if (!isValidShareCode(code)) { throw new ZError(11, 'invalid invite code') diff --git a/src/controllers/chest.controller.ts b/src/controllers/chest.controller.ts index 1c82ef0..cbe9117 100644 --- a/src/controllers/chest.controller.ts +++ b/src/controllers/chest.controller.ts @@ -9,6 +9,7 @@ import { generateNewChest } from 'services/game.svr' import { SCORE_OPEN_CHEST } from 'common/Constants' import { formatAddress } from 'zutils/utils/chain.util' import { isObjectIdString, isValidShareCode } from 'common/Utils' +import { checkReCaptcha } from 'services/google.svr' /** * 宝箱相关接口 @@ -94,6 +95,7 @@ class BoxController extends BaseController { @router('post /api/chest/enhance') async enhance(req) { new SyncLocker().checkLock(req) + await checkReCaptcha(req, 'chest_share') const { code } = req.params const user = req.user const uid = user.id diff --git a/src/services/discord.svr.ts b/src/services/discord.svr.ts index b41aff0..8989334 100644 --- a/src/services/discord.svr.ts +++ b/src/services/discord.svr.ts @@ -37,6 +37,9 @@ export async function checkJoinGuld(guid: string, uid: string) { if (res.code === 10013) { return false } + if (res.code) { + throw new Error(res.message) + } return true } catch (e) { return false @@ -54,6 +57,10 @@ export async function checkGotRole(guid: string, uid: string, roleId: string) { if (res.code === 10013) { return false } + if (res.code) { + // 如果有其他错误, 直接抛出异常, 让客户端重试 + throw new Error(res.message) + } if (res.roles.includes(roleId)) { return true } diff --git a/src/services/google.svr.ts b/src/services/google.svr.ts new file mode 100644 index 0000000..f88937d --- /dev/null +++ b/src/services/google.svr.ts @@ -0,0 +1,27 @@ +import { RECAPTCHA_MIN_SCORE } from 'common/Constants' +import { ZError } from 'zutils' + +export const checkReCaptcha = async (req: any, action: string) => { + if (!(process.env.NEED_RECAPTCHA && process.env.NEED_RECAPTCHA === '1')) { + return + } + const { rtoken } = req.params + if (!rtoken) { + throw new ZError(50, 'reCaptcha token is required') + } + const url = `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET}&response=${rtoken}` + const response = await fetch(url, { + method: 'POST', + }) + const data = await response.json() + if (!data.success) { + throw new ZError(51, `reCaptcha invalid`) + } + if (data.action !== action) { + throw new ZError(52, `reCaptcha action invalid`) + } + if (data.score < RECAPTCHA_MIN_SCORE) { + throw new ZError(53, `reCaptcha score invalid`) + } + return true +}