diff --git a/frontend/providers/costcenter/src/pages/_app.tsx b/frontend/providers/costcenter/src/pages/_app.tsx index a8ea00fb23c..184a002bb54 100644 --- a/frontend/providers/costcenter/src/pages/_app.tsx +++ b/frontend/providers/costcenter/src/pages/_app.tsx @@ -61,6 +61,7 @@ const App = ({ Component, pageProps }: AppProps) => { (async () => { try { const { data } = await request>('/api/platform/getAppConfig'); + state.setEnv('realNameRechargeLimit', !!data?.REALNAME_RECHARGE_LIMIT); state.setEnv('invoiceEnabled', !!data?.INVOICE_ENABLED); state.setEnv('transferEnabled', !!data?.TRANSFER_ENABLED); state.setEnv('rechargeEnabled', !!data?.RECHARGE_ENABLED); diff --git a/frontend/providers/costcenter/src/pages/api/account/gift-code.ts b/frontend/providers/costcenter/src/pages/api/account/gift-code.ts index 6a4a7d6836d..4646fb50fb8 100644 --- a/frontend/providers/costcenter/src/pages/api/account/gift-code.ts +++ b/frontend/providers/costcenter/src/pages/api/account/gift-code.ts @@ -1,5 +1,6 @@ import { makeAPIClientByHeader } from '@/service/backend/region'; import { jsonRes } from '@/service/backend/response'; +import { checkSealosUserIsRealName } from '@/utils/tools'; import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, resp: NextApiResponse) { @@ -28,6 +29,14 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse const client = await makeAPIClientByHeader(req, resp); if (!client) return; + const isRealName = await checkSealosUserIsRealName(client); + if (!isRealName) { + return jsonRes(resp, { + code: 403, + message: 'recharge is not allowed for non-real-name user' + }); + } + const response = await client.post('/account/v1alpha1/gift-code/use', body); const responseData = await response.data; if (response.status !== 200) { diff --git a/frontend/providers/costcenter/src/pages/api/account/payment/index.ts b/frontend/providers/costcenter/src/pages/api/account/payment/index.ts index 5016066c8d8..f87d5f42839 100644 --- a/frontend/providers/costcenter/src/pages/api/account/payment/index.ts +++ b/frontend/providers/costcenter/src/pages/api/account/payment/index.ts @@ -1,8 +1,10 @@ import { generatePaymentCrd, PaymentForm } from '@/constants/payment'; import { authSession } from '@/service/backend/auth'; import { ApplyYaml, GetUserDefaultNameSpace } from '@/service/backend/kubernetes'; +import { makeAPIClientByHeader } from '@/service/backend/region'; import { jsonRes } from '@/service/backend/response'; import { deFormatMoney } from '@/utils/format'; +import { checkSealosUserIsRealName } from '@/utils/tools'; import crypto from 'crypto'; import type { NextApiRequest, NextApiResponse } from 'next'; @@ -38,6 +40,17 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse return jsonRes(resp, { code: 401, message: 'user not found' }); } + const client = await makeAPIClientByHeader(req, resp); + if (!client) return; + + const isRealName = await checkSealosUserIsRealName(client); + if (!isRealName) { + return jsonRes(resp, { + code: 403, + message: 'recharge is not allowed for non-real-name user' + }); + } + // do payment const paymentName = crypto.randomUUID(); const namespace = GetUserDefaultNameSpace(kubeUser.name); diff --git a/frontend/providers/costcenter/src/pages/api/account/payment/stripe.ts b/frontend/providers/costcenter/src/pages/api/account/payment/stripe.ts index 87a4a5ea774..3b991e50917 100644 --- a/frontend/providers/costcenter/src/pages/api/account/payment/stripe.ts +++ b/frontend/providers/costcenter/src/pages/api/account/payment/stripe.ts @@ -1,7 +1,9 @@ import { generatePaymentCrd, PaymentForm } from '@/constants/payment'; import { authSession } from '@/service/backend/auth'; import { ApplyYaml, GetUserDefaultNameSpace } from '@/service/backend/kubernetes'; +import { makeAPIClientByHeader } from '@/service/backend/region'; import { jsonRes } from '@/service/backend/response'; +import { checkSealosUserIsRealName } from '@/utils/tools'; import crypto from 'crypto'; import type { NextApiRequest, NextApiResponse } from 'next'; @@ -23,6 +25,17 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse }); } + const client = await makeAPIClientByHeader(req, resp); + if (!client) return; + + const isRealName = await checkSealosUserIsRealName(client); + if (!isRealName) { + return jsonRes(resp, { + code: 403, + message: 'recharge is not allowed for non-real-name user' + }); + } + const k8s_username = kc.getUsers()[0].name; // do payment const paymentName = crypto.randomUUID(); diff --git a/frontend/providers/costcenter/src/pages/api/platform/getAppConfig.ts b/frontend/providers/costcenter/src/pages/api/platform/getAppConfig.ts index e08e1416f4c..024d627bba0 100644 --- a/frontend/providers/costcenter/src/pages/api/platform/getAppConfig.ts +++ b/frontend/providers/costcenter/src/pages/api/platform/getAppConfig.ts @@ -5,6 +5,7 @@ import { jsonRes } from '@/service/backend/response'; import { AppConfigType, DefaultAppConfig } from '@/types/config'; export type Response = { + REALNAME_RECHARGE_LIMIT: boolean; RECHARGE_ENABLED: boolean; TRANSFER_ENABLED: boolean; STRIPE_ENABLED: boolean; @@ -45,6 +46,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) initAppConfig(); jsonRes(res, { data: { + REALNAME_RECHARGE_LIMIT: global.AppConfig.costCenter.realNameRechargeLimit, RECHARGE_ENABLED: global.AppConfig.costCenter.recharge.enabled, TRANSFER_ENABLED: global.AppConfig.costCenter.transferEnabled, STRIPE_ENABLED: global.AppConfig.costCenter.recharge.payMethods.stripe.enabled, diff --git a/frontend/providers/costcenter/src/service/backend/region.ts b/frontend/providers/costcenter/src/service/backend/region.ts index cf4e2a35ffd..9a846f234f4 100644 --- a/frontend/providers/costcenter/src/service/backend/region.ts +++ b/frontend/providers/costcenter/src/service/backend/region.ts @@ -1,5 +1,5 @@ import { Region } from '@/types/region'; -import axios from 'axios'; +import axios, { AxiosInstance } from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; import { AccessTokenPayload, generateBillingToken, verifyInternalToken } from '../auth'; import { jsonRes } from './response'; @@ -53,7 +53,10 @@ export async function makeRegionListAPIClientByHeader(req: NextApiRequest, res: }); return clientList; } -export function makeAPIClient(region: Region | undefined | null, payload?: AccessTokenPayload) { +export function makeAPIClient( + region: Region | undefined | null, + payload?: AccessTokenPayload +): AxiosInstance { const baseURL = region?.accountSvc ? `http://${region?.accountSvc}` : global.AppConfig.costCenter.components.accountService.url; diff --git a/frontend/providers/costcenter/src/stores/env.ts b/frontend/providers/costcenter/src/stores/env.ts index 6f7c160c85c..9f5d9c60512 100644 --- a/frontend/providers/costcenter/src/stores/env.ts +++ b/frontend/providers/costcenter/src/stores/env.ts @@ -1,6 +1,7 @@ import { loadStripe } from '@stripe/stripe-js'; import { create } from 'zustand'; type EnvState = { + realNameRechargeLimit: boolean; rechargeEnabled: boolean; transferEnabled: boolean; invoiceEnabled: boolean; @@ -18,6 +19,7 @@ type EnvState = { }; const useEnvStore = create((set, get) => ({ + realNameRechargeLimit: false, rechargeEnabled: false, transferEnabled: false, invoiceEnabled: false, diff --git a/frontend/providers/costcenter/src/types/config.ts b/frontend/providers/costcenter/src/types/config.ts index df379ccd82f..d5262f00802 100644 --- a/frontend/providers/costcenter/src/types/config.ts +++ b/frontend/providers/costcenter/src/types/config.ts @@ -57,6 +57,7 @@ export type AppConfigType = { domain: string; }; costCenter: { + realNameRechargeLimit: boolean; transferEnabled: boolean; giftCodeEnabled: boolean; currencyType: string; @@ -75,6 +76,7 @@ export type AppConfigType = { export var DefaultAppConfig: AppConfigType = { costCenter: { + realNameRechargeLimit: false, giftCodeEnabled: true, transferEnabled: true, currencyType: 'shellCoin', diff --git a/frontend/providers/costcenter/src/utils/tools.ts b/frontend/providers/costcenter/src/utils/tools.ts index 10af19e8a2d..146dca38042 100644 --- a/frontend/providers/costcenter/src/utils/tools.ts +++ b/frontend/providers/costcenter/src/utils/tools.ts @@ -1,4 +1,6 @@ import { NextApiRequest } from 'next'; +import { AxiosInstance } from 'axios'; +import crypto from 'crypto'; export const retrySerially = (fn: () => Promise, times: number) => new Promise((res, rej) => { @@ -16,7 +18,6 @@ export const retrySerially = (fn: () => Promise, times: number) => }; attempt(); }); -import crypto from 'crypto'; export function genSign(secret: string, timestamp: number | string) { const stringToSign = `${timestamp}\n${secret}`; const hmac = crypto.createHmac('sha256', stringToSign); @@ -54,3 +55,33 @@ export function getClientIPFromRequest(req: NextApiRequest) { return undefined; } + +type RealNameInfoResponse = { + data: { + userID: string; + isRealName: boolean; + }; + error?: string; + message: string; +}; + +export const checkSealosUserIsRealName = async (client: AxiosInstance): Promise => { + try { + if (!global.AppConfig.costCenter.realNameRechargeLimit) { + return true; + } + + const response = await client.post('/account/v1alpha1/real-name-info'); + const realNameInfoData: RealNameInfoResponse = await response.data; + + if (realNameInfoData.error) { + console.error(realNameInfoData.error); + return false; + } + + return realNameInfoData.data.isRealName; + } catch (error) { + console.error(error); + return false; + } +};