From 42df67e6aa2e3d2d7146dfd8271d3f33a513a15c Mon Sep 17 00:00:00 2001 From: limbo Date: Fri, 30 May 2025 10:49:06 +0800 Subject: [PATCH] fix(desktop): Fix Tencent blocking real-name callback issue. (#5617) --- .../api/account/enterpriseRealNameVerify.ts | 15 ++++- .../api/account/faceIdRealNameAuthCallback.ts | 58 +++++++++++++++++-- .../api/account/generateRealNameQRcodeUri.ts | 19 ++++-- .../api/account/refreshRealNameQRecodeUri.ts | 19 ++++-- .../src/types/response/enterpriseRealName.ts | 1 + frontend/desktop/src/types/system.ts | 8 ++- 6 files changed, 100 insertions(+), 20 deletions(-) diff --git a/frontend/desktop/src/pages/api/account/enterpriseRealNameVerify.ts b/frontend/desktop/src/pages/api/account/enterpriseRealNameVerify.ts index f28a7e136..482047e00 100644 --- a/frontend/desktop/src/pages/api/account/enterpriseRealNameVerify.ts +++ b/frontend/desktop/src/pages/api/account/enterpriseRealNameVerify.ts @@ -107,8 +107,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } }); + if (enterprise && (enterprise?.additionalInfo as unknown as AdditionalInfo)?.isRestrictedUser) { + return jsonRes(res, { + code: 400, + message: "Restricted User Can't Enterprise Real Name Authentication" + }); + } + + let duplicateRealNameUser = false; + if (enterprise) { - realNameAuthReward = 0; + duplicateRealNameUser = true; } await globalPrisma.$transaction(async (globalPrisma) => { @@ -147,6 +156,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } }); + if (duplicateRealNameUser) { + return; + } + const userAccount = await globalPrisma.account.findUniqueOrThrow({ where: { userUid: userUid } }); diff --git a/frontend/desktop/src/pages/api/account/faceIdRealNameAuthCallback.ts b/frontend/desktop/src/pages/api/account/faceIdRealNameAuthCallback.ts index 4e3951314..8e381f896 100644 --- a/frontend/desktop/src/pages/api/account/faceIdRealNameAuthCallback.ts +++ b/frontend/desktop/src/pages/api/account/faceIdRealNameAuthCallback.ts @@ -1,4 +1,4 @@ -import { verifyAccessToken } from '@/services/backend/auth'; +import { verifyAuthenticationToken } from '@/services/backend/auth'; import { jsonRes } from '@/services/backend/response'; import { enableRealNameAuth } from '@/services/enable'; import * as tcsdk from 'tencentcloud-sdk-nodejs'; @@ -39,6 +39,7 @@ type AdditionalInfo = }; }; userMaterials?: string[]; + isRestrictedUser?: boolean; } | any; @@ -53,14 +54,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const bizToken = req.query?.BizToken as string; const extraQuery = req.query?.Extra as string; - const regionToken = extraQuery?.split('regionToken=')[1]; - if (!regionToken) { + const globalToken = extraQuery?.split('globalToken=')[1]; + if (!globalToken) { return jsonRes(res, { code: 400, message: 'Token is required' }); } - req.headers['authorization'] = regionToken; + req.headers['authorization'] = globalToken; - const payload = await verifyAccessToken(req.headers); + const payload = await verifyAuthenticationToken(req.headers); if (!payload) return jsonRes(res, { code: 401, message: 'Token is invaild' }); if (!realNameOSS) { @@ -203,8 +204,49 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } }); + if (realnameInfo && (realnameInfo?.additionalInfo as AdditionalInfo)?.isRestrictedUser) { + await globalPrisma.userRealNameInfo.update({ + where: { userUid: userUid }, + data: { + isVerified: false, + idVerifyFailedTimes: { increment: 1 }, + additionalInfo: additionalInfo + } + }); + + res.setHeader('Content-Type', 'text/html'); + return res.send(` + + + + + + Real Name Authentication + + + +

Restricted User Can't Real Name Authentication

+ + + `); + } + + let duplicateRealNameUser = false; + if (realnameInfo) { - realNameAuthReward = 0; + duplicateRealNameUser = true; } await globalPrisma.$transaction(async (globalPrisma) => { @@ -242,6 +284,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } }); + if (duplicateRealNameUser) { + return; + } + const userAccount = await globalPrisma.account.findUniqueOrThrow({ where: { userUid: userUid } }); diff --git a/frontend/desktop/src/pages/api/account/generateRealNameQRcodeUri.ts b/frontend/desktop/src/pages/api/account/generateRealNameQRcodeUri.ts index ba4a19258..e6d6070cc 100644 --- a/frontend/desktop/src/pages/api/account/generateRealNameQRcodeUri.ts +++ b/frontend/desktop/src/pages/api/account/generateRealNameQRcodeUri.ts @@ -2,7 +2,7 @@ import { jsonRes } from '@/services/backend/response'; import { enableRealNameAuth } from '@/services/enable'; import type { NextApiRequest, NextApiResponse } from 'next'; import * as tcsdk from 'tencentcloud-sdk-nodejs'; -import { verifyAccessToken } from '@/services/backend/auth'; +import { generateAuthenticationToken, verifyAccessToken } from '@/services/backend/auth'; import { globalPrisma } from '@/services/backend/db/init'; type TencentCloudFaceAuthConfig = { @@ -119,11 +119,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) currentTime - urlCreatedAt > urlExpirationTime; if (shouldGenerateNewUrl) { - const redirectUrl = `https://${global.AppConfig?.cloud.domain}/api/account/faceIdRealNameAuthCallback`; - const regionToken = req.headers['authorization'] as string; + const redirectUrl = + global.AppConfig?.common.realNameCallbackUrl || + `https://${global.AppConfig?.cloud.domain}/api/account/faceIdRealNameAuthCallback`; + + const globalToken = generateAuthenticationToken({ + userUid: payload.userUid, + userId: payload.userId + }); + urlResult = await generateRealNameQRcodeUri( redirectUrl, - regionToken, + globalToken, config as TencentCloudFaceAuthConfig ); @@ -171,7 +178,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) async function generateRealNameQRcodeUri( redirectUrl: string, - regionToken: string, + globalToken: string, config: TencentCloudFaceAuthConfig ): Promise { const FaceClient = tcsdk.faceid.v20180301.Client; @@ -194,7 +201,7 @@ async function generateRealNameQRcodeUri( const params = { RuleId: config.ruleId, RedirectUrl: redirectUrl, - Extra: `regionToken=${regionToken}` + Extra: `globalToken=${globalToken}` }; const data = await client.DetectAuth(params); diff --git a/frontend/desktop/src/pages/api/account/refreshRealNameQRecodeUri.ts b/frontend/desktop/src/pages/api/account/refreshRealNameQRecodeUri.ts index 210004009..5da3699a2 100644 --- a/frontend/desktop/src/pages/api/account/refreshRealNameQRecodeUri.ts +++ b/frontend/desktop/src/pages/api/account/refreshRealNameQRecodeUri.ts @@ -2,7 +2,7 @@ import { jsonRes } from '@/services/backend/response'; import { enableRealNameAuth } from '@/services/enable'; import type { NextApiRequest, NextApiResponse } from 'next'; import * as tcsdk from 'tencentcloud-sdk-nodejs'; -import { verifyAccessToken } from '@/services/backend/auth'; +import { generateAuthenticationToken, verifyAccessToken } from '@/services/backend/auth'; import { globalPrisma } from '@/services/backend/db/init'; type TencentCloudFaceAuthConfig = { @@ -117,11 +117,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const currentTime = new Date().getTime(); - const redirectUrl = `https://${global.AppConfig?.cloud.domain}/api/account/faceIdRealNameAuthCallback`; - const regionToken = req.headers['authorization'] as string; + const redirectUrl = + global.AppConfig?.common.realNameCallbackUrl || + `https://${global.AppConfig?.cloud.domain}/api/account/faceIdRealNameAuthCallback`; + + const globalToken = generateAuthenticationToken({ + userUid: payload.userUid, + userId: payload.userId + }); + const urlResult: QRCodeUrlResult = await generateRealNameQRcodeUri( redirectUrl, - regionToken, + globalToken, config as TencentCloudFaceAuthConfig ); @@ -161,7 +168,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) async function generateRealNameQRcodeUri( redirectUrl: string, - regionToken: string, + globalToken: string, config: TencentCloudFaceAuthConfig ): Promise { const FaceClient = tcsdk.faceid.v20180301.Client; @@ -184,7 +191,7 @@ async function generateRealNameQRcodeUri( const params = { RuleId: config.ruleId, RedirectUrl: redirectUrl, - Extra: `regionToken=${regionToken}` + Extra: `globalToken=${globalToken}` }; const data = await client.DetectAuth(params); diff --git a/frontend/desktop/src/types/response/enterpriseRealName.ts b/frontend/desktop/src/types/response/enterpriseRealName.ts index a480d2879..7f0885427 100644 --- a/frontend/desktop/src/types/response/enterpriseRealName.ts +++ b/frontend/desktop/src/types/response/enterpriseRealName.ts @@ -26,4 +26,5 @@ export interface AdditionalInfo { contactInfo: string; transAmt: string; authTimes: number; + isRestrictedUser?: boolean; } diff --git a/frontend/desktop/src/types/system.ts b/frontend/desktop/src/types/system.ts index a27cf5309..3bf31e962 100644 --- a/frontend/desktop/src/types/system.ts +++ b/frontend/desktop/src/types/system.ts @@ -13,6 +13,7 @@ export type CommonConfigType = { enterpriseRealNameAuthEnabled: boolean; realNameAuthEnabled: boolean; realNameReward: number; + realNameCallbackUrl?: string; guideEnabled: boolean; apiEnabled: boolean; rechargeEnabled: boolean; @@ -26,7 +27,12 @@ export type CommonConfigType = { export type CommonClientConfigType = DeepRequired< Omit< CommonConfigType, - 'apiEnabled' | 'objectstorageUrl' | 'applaunchpadUrl' | 'dbproviderUrl' | 'templateUrl' + | 'apiEnabled' + | 'objectstorageUrl' + | 'applaunchpadUrl' + | 'dbproviderUrl' + | 'templateUrl' + | 'realNameCallbackUrl' > >; export type DatabaseConfigType = {