🐛 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,
cipher: 'chacha20-ietf-poly1305',
server_key: null,
security: 'none',
host: null,
path: null,
obfs: 'none',
obfs_host: null,
obfs_path: null,
sni: null,
allow_insecure: null,
cert_mode: 'none',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1350,6 +1350,26 @@ declare namespace API {
node_secret: string;
node_pull_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 = {
@ -1554,6 +1574,14 @@ declare namespace API {
encryption_client_padding?: string;
/** encryption password */
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 = {

View File

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

View File

@ -363,6 +363,26 @@ declare namespace API {
node_secret: string;
node_pull_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 = {
@ -562,6 +582,14 @@ declare namespace API {
encryption_client_padding?: string;
/** encryption password */
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 = {

View File

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

View File

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

View File

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

View File

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

View File

@ -363,6 +363,26 @@ declare namespace API {
node_secret: string;
node_pull_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 = {
@ -562,6 +582,14 @@ declare namespace API {
encryption_client_padding?: string;
/** encryption password */
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 = {

View File

@ -378,6 +378,26 @@ declare namespace API {
node_secret: string;
node_pull_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 = {
@ -601,6 +621,14 @@ declare namespace API {
encryption_client_padding?: string;
/** encryption password */
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 = {