diff --git a/frontend/src/pages/clients/ClientBulkAdjustModal.tsx b/frontend/src/pages/clients/ClientBulkAdjustModal.tsx
index b13dcdea..e9f770c5 100644
--- a/frontend/src/pages/clients/ClientBulkAdjustModal.tsx
+++ b/frontend/src/pages/clients/ClientBulkAdjustModal.tsx
@@ -2,6 +2,8 @@ import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Alert, Form, InputNumber, Modal, message } from 'antd';
+import { ClientBulkAdjustFormSchema } from '@/schemas/client';
+
const GB = 1024 * 1024 * 1024;
interface ClientBulkAdjustModalProps {
@@ -26,12 +28,15 @@ export default function ClientBulkAdjustModal({ open, count, onOpenChange, onSub
}, [open]);
async function handleOk() {
- const days = Math.trunc(Number(addDays) || 0);
- const gb = Number(addGB) || 0;
- if (days === 0 && gb === 0) {
- messageApi.warning(t('pages.clients.bulkAdjustNothing'));
+ const validated = ClientBulkAdjustFormSchema.safeParse({
+ addDays: Math.trunc(Number(addDays) || 0),
+ addGB: Number(addGB) || 0,
+ });
+ if (!validated.success) {
+ messageApi.warning(t(validated.error.issues[0]?.message ?? 'somethingWentWrong'));
return;
}
+ const { addDays: days, addGB: gb } = validated.data;
setSubmitting(true);
try {
const bytes = Math.trunc(gb * GB);
diff --git a/frontend/src/pages/index/CustomGeoFormModal.tsx b/frontend/src/pages/index/CustomGeoFormModal.tsx
index 9f4b087e..f8f8cb2a 100644
--- a/frontend/src/pages/index/CustomGeoFormModal.tsx
+++ b/frontend/src/pages/index/CustomGeoFormModal.tsx
@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Form, Input, message, Modal, Select } from 'antd';
import { HttpUtil } from '@/utils';
+import { CustomGeoFormSchema } from '@/schemas/xray';
export interface CustomGeoRecord {
id: number;
@@ -46,37 +47,18 @@ export default function CustomGeoFormModal({
}
}, [open, record]);
- function validate(): boolean {
- if (!/^[a-z0-9_-]+$/.test(alias || '')) {
- messageApi.error(t('pages.index.customGeoValidationAlias'));
- return false;
- }
- const u = (url || '').trim();
- if (!/^https?:\/\//i.test(u)) {
- messageApi.error(t('pages.index.customGeoValidationUrl'));
- return false;
- }
- try {
- const parsed = new URL(u);
- if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
- messageApi.error(t('pages.index.customGeoValidationUrl'));
- return false;
- }
- } catch {
- messageApi.error(t('pages.index.customGeoValidationUrl'));
- return false;
- }
- return true;
- }
-
async function submit() {
- if (!validate()) return;
+ const validated = CustomGeoFormSchema.safeParse({ type, alias, url });
+ if (!validated.success) {
+ messageApi.error(t(validated.error.issues[0]?.message ?? 'somethingWentWrong'));
+ return;
+ }
setSaving(true);
try {
const apiUrl = editing
? `/panel/api/custom-geo/update/${record!.id}`
: '/panel/api/custom-geo/add';
- const msg = await HttpUtil.post(apiUrl, { type, alias, url });
+ const msg = await HttpUtil.post(apiUrl, validated.data);
if (msg?.success) {
onSaved();
onClose();
diff --git a/frontend/src/pages/settings/TwoFactorModal.tsx b/frontend/src/pages/settings/TwoFactorModal.tsx
index b686926c..1aacc20a 100644
--- a/frontend/src/pages/settings/TwoFactorModal.tsx
+++ b/frontend/src/pages/settings/TwoFactorModal.tsx
@@ -4,6 +4,7 @@ import { Button, Divider, Input, Modal, QRCode, message } from 'antd';
import * as OTPAuth from 'otpauth';
import { ClipboardManager } from '@/utils';
+import { TotpCodeSchema } from '@/schemas/login';
import './TwoFactorModal.css';
type Type = 'set' | 'confirm';
@@ -61,12 +62,17 @@ export default function TwoFactorModal({
}
function onOk() {
+ const codeOk = TotpCodeSchema.safeParse(enteredCode);
+ if (!codeOk.success) {
+ messageApi.error(t(codeOk.error.issues[0]?.message ?? 'pages.settings.security.twoFactorModalError'));
+ return;
+ }
if (type === 'confirm' && !token) {
- close(true, enteredCode);
+ close(true, codeOk.data);
return;
}
if (!totpRef.current) return;
- if (totpRef.current.generate() === enteredCode) {
+ if (totpRef.current.generate() === codeOk.data) {
close(true);
} else {
messageApi.error(t('pages.settings.security.twoFactorModalError'));
@@ -92,7 +98,7 @@ export default function TwoFactorModal({
onCancel={onCancel}
footer={[
,
-