🐛 fix: Update protocol fields to use 'obfs' instead of 'security' and adjust related configurations

This commit is contained in:
web 2025-09-28 06:57:41 -07:00
parent fc43de16f0
commit 4abdd367ee
15 changed files with 164 additions and 64 deletions

View File

@ -10,9 +10,9 @@ export function getProtocolDefaultConfig(proto: ProtocolType) {
port: null, port: null,
cipher: 'chacha20-ietf-poly1305', cipher: 'chacha20-ietf-poly1305',
server_key: null, server_key: null,
security: 'none', obfs: 'none',
host: null, obfs_host: null,
path: null, obfs_path: null,
sni: null, sni: null,
allow_insecure: null, allow_insecure: null,
cert_mode: 'none', cert_mode: 'none',

View File

@ -65,42 +65,42 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
].includes(p.cipher), ].includes(p.cipher),
}, },
{ {
name: 'security', name: 'obfs',
type: 'select', type: 'select',
label: 'security', label: 'obfs',
options: SECURITY.shadowsocks, options: ['none', 'http', 'tls'],
defaultValue: 'none', defaultValue: 'none',
group: 'security', group: 'obfs',
}, },
{ {
name: 'host', name: 'obfs_host',
type: 'input', type: 'input',
label: 'host', label: 'host',
placeholder: 'e.g. www.bing.com', placeholder: 'e.g. www.bing.com',
group: 'security', group: 'obfs',
condition: (p) => p.security && p.security !== 'none', condition: (p) => p.obfs && p.obfs !== 'none',
}, },
{ {
name: 'path', name: 'obfs_path',
type: 'input', type: 'input',
label: 'path', label: 'path',
placeholder: 'e.g. /path/to/obfs', placeholder: 'e.g. /path/to/obfs',
group: 'security', group: 'obfs',
condition: (p) => p.security && p.security !== 'none', condition: (p) => p.obfs && p.obfs !== 'none',
}, },
{ {
name: 'sni', name: 'sni',
type: 'input', type: 'input',
label: 'security_sni', label: 'security_sni',
group: 'security', group: 'security',
condition: (p) => p.security === 'tls', condition: (p) => p.obfs === 'tls',
}, },
{ {
name: 'allow_insecure', name: 'allow_insecure',
type: 'switch', type: 'switch',
label: 'security_allow_insecure', label: 'security_allow_insecure',
group: 'security', group: 'security',
condition: (p) => p.security === 'tls', condition: (p) => p.obfs === 'tls',
}, },
{ {
name: 'cert_mode', name: 'cert_mode',
@ -109,7 +109,7 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
options: CERT_MODES, options: CERT_MODES,
defaultValue: 'none', defaultValue: 'none',
group: 'security', group: 'security',
condition: (p) => p.security === 'tls', condition: (p) => p.obfs === 'tls',
}, },
{ {
name: 'cert_dns_provider', name: 'cert_dns_provider',
@ -117,7 +117,7 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
label: 'cert_dns_provider', label: 'cert_dns_provider',
placeholder: 'e.g. cloudflare, aliyun', placeholder: 'e.g. cloudflare, aliyun',
group: 'security', group: 'security',
condition: (p) => p.security === 'tls' && p.cert_mode === 'dns', condition: (p) => p.obfs === 'tls' && p.cert_mode === 'dns',
}, },
{ {
name: 'cert_dns_env', name: 'cert_dns_env',
@ -126,7 +126,7 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
placeholder: placeholder:
'CF_DNS_API_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz\nALI_ACCESS_KEY_ID=your_access_key_id\nALI_ACCESS_KEY_SECRET=your_access_key_secret', 'CF_DNS_API_TOKEN=1234567890abcdefghijklmnopqrstuvwxyz\nALI_ACCESS_KEY_ID=your_access_key_id\nALI_ACCESS_KEY_SECRET=your_access_key_secret',
group: 'security', group: 'security',
condition: (p) => p.security === 'tls' && p.cert_mode === 'dns', condition: (p) => p.obfs === 'tls' && p.cert_mode === 'dns',
}, },
], ],
vmess: [ vmess: [

View File

@ -26,9 +26,9 @@ const ss = z.object({
port: nullablePort, port: nullablePort,
cipher: z.enum(SS_CIPHERS).nullish(), cipher: z.enum(SS_CIPHERS).nullish(),
server_key: nullableString, server_key: nullableString,
security: z.enum(SECURITY.shadowsocks).nullish(), obfs: z.enum(['none', 'http', 'tls'] as const).nullish(),
host: nullableString, obfs_host: nullableString,
path: nullableString, obfs_path: nullableString,
cert_mode: z.enum(CERT_MODES).nullish(), cert_mode: z.enum(CERT_MODES).nullish(),
cert_dns_provider: nullableString, cert_dns_provider: nullableString,
cert_dns_env: nullableString, cert_dns_env: nullableString,

View File

@ -245,7 +245,7 @@ export default function ServersPage() {
key='edit' key='edit'
trigger={t('edit')} trigger={t('edit')}
title={t('drawerEditTitle')} title={t('drawerEditTitle')}
initialValues={row as any} initialValues={row}
loading={loading} loading={loading}
onSubmit={async (values) => { onSubmit={async (values) => {
setLoading(true); setLoading(true);

View File

@ -44,30 +44,31 @@ import { toast } from 'sonner';
import { z } from 'zod'; import { z } from 'zod';
const dnsConfigSchema = z.object({ const dnsConfigSchema = z.object({
proto: z.enum(['tcp', 'udp', 'tls', 'https', 'quic']), proto: z.string(), // z.enum(['tcp', 'udp', 'tls', 'https', 'quic']),
address: z.string(), address: z.string(),
domains: z.array(z.string()), domains: z.array(z.string()),
}); });
const outboundConfigSchema = z.object({ const outboundConfigSchema = z.object({
name: z.string(), name: z.string(),
protocol: z.enum([ protocol: z.string(),
'http', // z.enum([
'https', // 'http',
'socks5', // 'https',
'shadowsocks', // 'socks5',
'vmess', // 'shadowsocks',
'vless', // 'vmess',
'trojan', // 'vless',
'hysteria2', // 'trojan',
'tuic', // 'hysteria2',
'naive', // 'tuic',
'brook', // 'naive',
'snell', // 'brook',
'wireguard', // 'snell',
'direct', // 'wireguard',
'reject', // 'direct',
]), // 'reject',
// ]),
address: z.string(), address: z.string(),
port: z.number(), port: z.number(),
password: z.string().optional(), password: z.string().optional(),
@ -120,11 +121,11 @@ export default function ServerConfig() {
node_secret: cfgResp.node_secret ?? '', node_secret: cfgResp.node_secret ?? '',
node_pull_interval: cfgResp.node_pull_interval as number | undefined, node_pull_interval: cfgResp.node_pull_interval as number | undefined,
node_push_interval: cfgResp.node_push_interval as number | undefined, node_push_interval: cfgResp.node_push_interval as number | undefined,
traffic_report_threshold: (cfgResp as any).traffic_report_threshold as number | undefined, traffic_report_threshold: cfgResp.traffic_report_threshold as number | undefined,
ip_strategy: (cfgResp as any).ip_strategy as 'prefer_ipv4' | 'prefer_ipv6' | undefined, ip_strategy: cfgResp.ip_strategy as 'prefer_ipv4' | 'prefer_ipv6' | undefined,
dns: (cfgResp as any).dns || [], dns: cfgResp.dns || [],
block: (cfgResp as any).block || [], block: cfgResp.block || [],
outbound: (cfgResp as any).outbound || [], outbound: cfgResp.outbound || [],
}); });
} }
}, [cfgResp, form]); }, [cfgResp, form]);
@ -355,16 +356,12 @@ export default function ServerConfig() {
domains: Array.isArray(item.domains) ? item.domains.join('\n') : '', domains: Array.isArray(item.domains) ? item.domains.join('\n') : '',
}))} }))}
onChange={(values) => { onChange={(values) => {
// 转换 domains 字符串为数组
const converted = values.map((item: any) => ({ const converted = values.map((item: any) => ({
proto: item.proto, proto: item.proto,
address: item.address, address: item.address,
domains: domains:
typeof item.domains === 'string' typeof item.domains === 'string'
? item.domains ? item.domains.split('\n').map((d: string) => d.trim())
.split('\n')
.map((d: string) => d.trim())
.filter(Boolean)
: item.domains || [], : item.domains || [],
})); }));
field.onChange(converted); field.onChange(converted);
@ -446,7 +443,6 @@ export default function ServerConfig() {
rules: Array.isArray(item.rules) ? item.rules.join('\n') : '', rules: Array.isArray(item.rules) ? item.rules.join('\n') : '',
}))} }))}
onChange={(values) => { onChange={(values) => {
// 转换 rules 字符串为数组
const converted = values.map((item: any) => ({ const converted = values.map((item: any) => ({
name: item.name, name: item.name,
protocol: item.protocol, protocol: item.protocol,
@ -455,10 +451,7 @@ export default function ServerConfig() {
password: item.password, password: item.password,
rules: rules:
typeof item.rules === 'string' typeof item.rules === 'string'
? item.rules ? item.rules.split('\n').map((r: string) => r.trim())
.split('\n')
.map((r: string) => r.trim())
.filter(Boolean)
: item.rules || [], : item.rules || [],
})); }));
field.onChange(converted); field.onChange(converted);
@ -482,10 +475,7 @@ export default function ServerConfig() {
placeholder={t('server_config.fields.block_rules_placeholder')} placeholder={t('server_config.fields.block_rules_placeholder')}
value={(field.value || []).join('\n')} value={(field.value || []).join('\n')}
onChange={(e) => { onChange={(e) => {
const lines = e.target.value const lines = e.target.value.split('\n').map((line) => line.trim());
.split('\n')
.map((line) => line.trim())
.filter(Boolean);
field.onChange(lines); field.onChange(lines);
}} }}
rows={10} rows={10}

View File

@ -170,6 +170,7 @@ export default function UserForm<T extends Record<string, any>>({
<FormLabel>{t('password')}</FormLabel> <FormLabel>{t('password')}</FormLabel>
<FormControl> <FormControl>
<EnhancedInput <EnhancedInput
autoComplete='new-password'
placeholder={t('passwordPlaceholder')} placeholder={t('passwordPlaceholder')}
{...field} {...field}
onValueChange={(value) => { onValueChange={(value) => {

View File

@ -1350,6 +1350,26 @@ declare namespace API {
node_secret: string; node_secret: string;
node_pull_interval: number; node_pull_interval: number;
node_push_interval: number; node_push_interval: number;
traffic_report_threshold: number;
ip_strategy: string;
dns: NodeDNS[];
block: string[];
outbound: NodeOutbound[];
};
type NodeDNS = {
proto: string;
address: string;
domains: string[];
};
type NodeOutbound = {
name: string;
protocol: string;
address: string;
port: number;
password: string;
rules: string[];
}; };
type NodeRelay = { type NodeRelay = {
@ -1554,6 +1574,14 @@ declare namespace API {
encryption_client_padding?: string; encryption_client_padding?: string;
/** encryption password */ /** encryption password */
encryption_password?: string; encryption_password?: string;
/** Traffic ratio, default is 1 */
ratio?: number;
/** Certificate mode, `none``http``dns``self` */
cert_mode?: string;
/** DNS provider for certificate */
cert_dns_provider?: string;
/** Environment for DNS provider */
cert_dns_env?: string;
}; };
type PubilcRegisterConfig = { type PubilcRegisterConfig = {

View File

@ -1,5 +1,5 @@
// @ts-ignore // @ts-ignore
/* eslint-disable */
import request from '@/utils/request'; import request from '@/utils/request';
/** Apple Login Callback POST /v1/auth/oauth/callback/apple */ /** Apple Login Callback POST /v1/auth/oauth/callback/apple */

View File

@ -363,6 +363,26 @@ declare namespace API {
node_secret: string; node_secret: string;
node_pull_interval: number; node_pull_interval: number;
node_push_interval: number; node_push_interval: number;
traffic_report_threshold: number;
ip_strategy: string;
dns: NodeDNS[];
block: string[];
outbound: NodeOutbound[];
};
type NodeDNS = {
proto: string;
address: string;
domains: string[];
};
type NodeOutbound = {
name: string;
protocol: string;
address: string;
port: number;
password: string;
rules: string[];
}; };
type NodeRelay = { type NodeRelay = {
@ -562,6 +582,14 @@ declare namespace API {
encryption_client_padding?: string; encryption_client_padding?: string;
/** encryption password */ /** encryption password */
encryption_password?: string; encryption_password?: string;
/** Traffic ratio, default is 1 */
ratio?: number;
/** Certificate mode, `none``http``dns``self` */
cert_mode?: string;
/** DNS provider for certificate */
cert_dns_provider?: string;
/** Environment for DNS provider */
cert_dns_env?: string;
}; };
type PubilcRegisterConfig = { type PubilcRegisterConfig = {

View File

@ -225,7 +225,6 @@ export default function Content() {
{Array.from({ length: 16 }).map((_, i) => { {Array.from({ length: 16 }).map((_, i) => {
const row = Math.floor(i / 4); const row = Math.floor(i / 4);
const col = i % 4; const col = i % 4;
// 计算位置百分比
const top = 10 + row * 25 + (col % 2 === 0 ? 5 : -5); const top = 10 + row * 25 + (col % 2 === 0 ? 5 : -5);
const left = 5 + col * 30 + (row % 2 === 0 ? 0 : 10); const left = 5 + col * 30 + (row % 2 === 0 ? 0 : 10);

View File

@ -39,7 +39,6 @@ const DurationSelector: React.FC<DurationSelectorProps> = ({
</div> </div>
); );
// 查找当前选中项的折扣信息
const currentDiscount = discounts?.find((item) => item.quantity === quantity)?.discount; const currentDiscount = discounts?.find((item) => item.quantity === quantity)?.discount;
const discountPercentage = currentDiscount ? 100 - currentDiscount : 0; const discountPercentage = currentDiscount ? 100 - currentDiscount : 0;

View File

@ -52,7 +52,6 @@ export default function Renewal({ id, subscribe }: Readonly<RenewalProps>) {
subscribe_id: subscribe.id, subscribe_id: subscribe.id,
} as API.PurchaseOrderRequest); } as API.PurchaseOrderRequest);
const result = data.data; const result = data.data;
// 请求成功时保存数据
if (result) { if (result) {
lastSuccessOrderRef.current = result; lastSuccessOrderRef.current = result;
} }

View File

@ -1,5 +1,5 @@
// @ts-ignore // @ts-ignore
/* eslint-disable */
import request from '@/utils/request'; import request from '@/utils/request';
/** Apple Login Callback POST /v1/auth/oauth/callback/apple */ /** Apple Login Callback POST /v1/auth/oauth/callback/apple */

View File

@ -363,6 +363,26 @@ declare namespace API {
node_secret: string; node_secret: string;
node_pull_interval: number; node_pull_interval: number;
node_push_interval: number; node_push_interval: number;
traffic_report_threshold: number;
ip_strategy: string;
dns: NodeDNS[];
block: string[];
outbound: NodeOutbound[];
};
type NodeDNS = {
proto: string;
address: string;
domains: string[];
};
type NodeOutbound = {
name: string;
protocol: string;
address: string;
port: number;
password: string;
rules: string[];
}; };
type NodeRelay = { type NodeRelay = {
@ -562,6 +582,14 @@ declare namespace API {
encryption_client_padding?: string; encryption_client_padding?: string;
/** encryption password */ /** encryption password */
encryption_password?: string; encryption_password?: string;
/** Traffic ratio, default is 1 */
ratio?: number;
/** Certificate mode, `none``http``dns``self` */
cert_mode?: string;
/** DNS provider for certificate */
cert_dns_provider?: string;
/** Environment for DNS provider */
cert_dns_env?: string;
}; };
type PubilcRegisterConfig = { type PubilcRegisterConfig = {

View File

@ -378,6 +378,26 @@ declare namespace API {
node_secret: string; node_secret: string;
node_pull_interval: number; node_pull_interval: number;
node_push_interval: number; node_push_interval: number;
traffic_report_threshold: number;
ip_strategy: string;
dns: NodeDNS[];
block: string[];
outbound: NodeOutbound[];
};
type NodeDNS = {
proto: string;
address: string;
domains: string[];
};
type NodeOutbound = {
name: string;
protocol: string;
address: string;
port: number;
password: string;
rules: string[];
}; };
type NodeRelay = { type NodeRelay = {
@ -601,6 +621,14 @@ declare namespace API {
encryption_client_padding?: string; encryption_client_padding?: string;
/** encryption password */ /** encryption password */
encryption_password?: string; encryption_password?: string;
/** Traffic ratio, default is 1 */
ratio?: number;
/** Certificate mode, `none``http``dns``self` */
cert_mode?: string;
/** DNS provider for certificate */
cert_dns_provider?: string;
/** Environment for DNS provider */
cert_dns_env?: string;
}; };
type PubilcRegisterConfig = { type PubilcRegisterConfig = {