🐛 fix: Added the enabled field in the protocol configuration, updated the related type definition and default configuration

This commit is contained in:
web 2025-09-16 10:17:39 -07:00
parent d6854076fe
commit 2b0cf9a46d
14 changed files with 223 additions and 107 deletions

View File

@ -1,16 +1,16 @@
<a name="readme-top"></a>
# Changelog
## [1.4.3](https://github.com/perfect-panel/ppanel-web/compare/v1.4.2...v1.4.3) (2025-09-16)
### 🐛 Bug Fixes
* Add success toast message for sorting in nodes and servers pages ([2d5175d](https://github.com/perfect-panel/ppanel-web/commit/2d5175d))
* Implement encryption and obfuscation features in protocol configuration ([54de16b](https://github.com/perfect-panel/ppanel-web/commit/54de16b))
* Refactor toB64 function to toB64Url for URL-safe base64 encoding in VlessX25519Pair generation ([8700cf6](https://github.com/perfect-panel/ppanel-web/commit/8700cf6))
* Simplify initialValues assignment and update node submission logic in NodesPage ([05d6c89](https://github.com/perfect-panel/ppanel-web/commit/05d6c89))
* Update bun.lockb to reflect dependency changes ([ebcebd7](https://github.com/perfect-panel/ppanel-web/commit/ebcebd7))
- Add success toast message for sorting in nodes and servers pages ([2d5175d](https://github.com/perfect-panel/ppanel-web/commit/2d5175d))
- Implement encryption and obfuscation features in protocol configuration ([54de16b](https://github.com/perfect-panel/ppanel-web/commit/54de16b))
- Refactor toB64 function to toB64Url for URL-safe base64 encoding in VlessX25519Pair generation ([8700cf6](https://github.com/perfect-panel/ppanel-web/commit/8700cf6))
- Simplify initialValues assignment and update node submission logic in NodesPage ([05d6c89](https://github.com/perfect-panel/ppanel-web/commit/05d6c89))
- Update bun.lockb to reflect dependency changes ([ebcebd7](https://github.com/perfect-panel/ppanel-web/commit/ebcebd7))
<a name="readme-top"></a>

View File

@ -1,3 +1,4 @@
import { XHTTP_MODES } from './constants';
import type { ProtocolType } from './types';
export function getProtocolDefaultConfig(proto: ProtocolType) {
@ -5,6 +6,7 @@ export function getProtocolDefaultConfig(proto: ProtocolType) {
case 'shadowsocks':
return {
type: 'shadowsocks',
enable: false,
port: null,
cipher: 'chacha20-ietf-poly1305',
server_key: null,
@ -13,14 +15,36 @@ export function getProtocolDefaultConfig(proto: ProtocolType) {
obfs_path: null,
} as any;
case 'vmess':
return { type: 'vmess', port: null, transport: 'tcp', security: 'none' } as any;
return {
type: 'vmess',
enable: false,
port: null,
transport: 'tcp',
security: 'none',
} as any;
case 'vless':
return { type: 'vless', port: null, transport: 'tcp', security: 'none', flow: 'none' } as any;
return {
type: 'vless',
enable: false,
port: null,
transport: 'tcp',
security: 'none',
flow: 'none',
xhttp_mode: XHTTP_MODES[0], // 'auto'
xhttp_extra: null,
} as any;
case 'trojan':
return { type: 'trojan', port: null, transport: 'tcp', security: 'tls' } as any;
return {
type: 'trojan',
enable: false,
port: null,
transport: 'tcp',
security: 'tls',
} as any;
case 'hysteria2':
return {
type: 'hysteria2',
enable: false,
port: null,
hop_ports: null,
hop_interval: null,
@ -33,6 +57,7 @@ export function getProtocolDefaultConfig(proto: ProtocolType) {
case 'tuic':
return {
type: 'tuic',
enable: false,
port: null,
disable_sni: false,
reduce_rtt: false,
@ -46,17 +71,20 @@ export function getProtocolDefaultConfig(proto: ProtocolType) {
case 'socks':
return {
type: 'socks',
enable: false,
port: null,
} as any;
case 'naive':
return {
type: 'naive',
enable: false,
port: null,
security: 'none',
} as any;
case 'http':
return {
type: 'http',
enable: false,
port: null,
security: 'none',
} as any;

View File

@ -211,7 +211,7 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
condition: (p) => p.transport === 'grpc',
},
{
name: 'mode',
name: 'xhttp_mode',
type: 'select',
label: 'mode',
options: XHTTP_MODES,
@ -220,7 +220,7 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
condition: (p) => p.transport === 'xhttp',
},
{
name: 'extra',
name: 'xhttp_extra',
type: 'textarea',
label: 'extra',
placeholder: '{}',

View File

@ -10,6 +10,7 @@ import {
TRANSPORTS,
TUIC_CONGESTION,
TUIC_UDP_RELAY_MODES,
XHTTP_MODES,
} from './constants';
const nullableString = z.string().nullish();
@ -18,9 +19,10 @@ const nullablePort = z.number().int().min(0).max(65535).nullish();
const ss = z.object({
type: z.literal('shadowsocks'),
enable: nullableBool,
host: nullableString,
port: nullablePort,
cipher: z.enum(SS_CIPHERS as any).nullish(),
cipher: z.enum(SS_CIPHERS).nullish(),
server_key: nullableString,
obfs: z.enum(['none', 'http', 'tls'] as const).nullish(),
obfs_host: nullableString,
@ -29,10 +31,11 @@ const ss = z.object({
const vmess = z.object({
type: z.literal('vmess'),
enable: nullableBool,
host: nullableString,
port: nullablePort,
transport: z.enum(TRANSPORTS.vmess as any).nullish(),
security: z.enum(SECURITY.vmess as any).nullish(),
transport: z.enum(TRANSPORTS.vmess).nullish(),
security: z.enum(SECURITY.vmess).nullish(),
path: nullableString,
service_name: nullableString,
sni: nullableString,
@ -42,13 +45,14 @@ const vmess = z.object({
const vless = z.object({
type: z.literal('vless'),
enable: nullableBool,
host: nullableString,
port: nullablePort,
transport: z.enum(TRANSPORTS.vless as any).nullish(),
security: z.enum(SECURITY.vless as any).nullish(),
transport: z.enum(TRANSPORTS.vless).nullish(),
security: z.enum(SECURITY.vless).nullish(),
path: nullableString,
service_name: nullableString,
flow: z.enum(FLOWS.vless as any).nullish(),
flow: z.enum(FLOWS.vless).nullish(),
sni: nullableString,
allow_insecure: nullableBool,
fingerprint: nullableString,
@ -57,11 +61,11 @@ const vless = z.object({
reality_private_key: nullableString,
reality_public_key: nullableString,
reality_short_id: nullableString,
mode: nullableString,
extra: nullableString,
encryption: z.enum(ENCRYPTION_TYPES as any).nullish(),
encryption_mode: z.enum(ENCRYPTION_MODES as any).nullish(),
encryption_rtt: z.enum(ENCRYPTION_RTT as any).nullish(),
xhttp_mode: z.enum(XHTTP_MODES).nullish(),
xhttp_extra: nullableString,
encryption: z.enum(ENCRYPTION_TYPES).nullish(),
encryption_mode: z.enum(ENCRYPTION_MODES).nullish(),
encryption_rtt: z.enum(ENCRYPTION_RTT).nullish(),
encryption_ticket: nullableString,
encryption_server_padding: nullableString,
encryption_private_key: nullableString,
@ -71,10 +75,11 @@ const vless = z.object({
const trojan = z.object({
type: z.literal('trojan'),
enable: nullableBool,
host: nullableString,
port: nullablePort,
transport: z.enum(TRANSPORTS.trojan as any).nullish(),
security: z.enum(SECURITY.trojan as any).nullish(),
transport: z.enum(TRANSPORTS.trojan).nullish(),
security: z.enum(SECURITY.trojan).nullish(),
path: nullableString,
service_name: nullableString,
sni: nullableString,
@ -84,12 +89,13 @@ const trojan = z.object({
const hysteria2 = z.object({
type: z.literal('hysteria2'),
enable: nullableBool,
hop_ports: nullableString,
hop_interval: z.number().nullish(),
obfs_password: nullableString,
obfs: z.enum(['none', 'salamander'] as const).nullish(),
port: nullablePort,
security: z.enum(SECURITY.hysteria2 as any).nullish(),
security: z.enum(SECURITY.hysteria2).nullish(),
sni: nullableString,
allow_insecure: nullableBool,
fingerprint: nullableString,
@ -99,13 +105,14 @@ const hysteria2 = z.object({
const tuic = z.object({
type: z.literal('tuic'),
enable: nullableBool,
host: nullableString,
port: nullablePort,
disable_sni: z.boolean().nullish(),
reduce_rtt: z.boolean().nullish(),
udp_relay_mode: z.enum(TUIC_UDP_RELAY_MODES as any).nullish(),
congestion_controller: z.enum(TUIC_CONGESTION as any).nullish(),
security: z.enum(SECURITY.tuic as any).nullish(),
udp_relay_mode: z.enum(TUIC_UDP_RELAY_MODES).nullish(),
congestion_controller: z.enum(TUIC_CONGESTION).nullish(),
security: z.enum(SECURITY.tuic).nullish(),
sni: nullableString,
allow_insecure: nullableBool,
fingerprint: nullableString,
@ -113,8 +120,9 @@ const tuic = z.object({
const anytls = z.object({
type: z.literal('anytls'),
enable: nullableBool,
port: nullablePort,
security: z.enum(SECURITY.anytls as any).nullish(),
security: z.enum(SECURITY.anytls).nullish(),
sni: nullableString,
allow_insecure: nullableBool,
fingerprint: nullableString,
@ -123,13 +131,15 @@ const anytls = z.object({
const socks = z.object({
type: z.literal('socks'),
enable: nullableBool,
port: nullablePort,
});
const naive = z.object({
type: z.literal('naive'),
enable: nullableBool,
port: nullablePort,
security: z.enum(SECURITY.naive as any).nullish(),
security: z.enum(SECURITY.naive).nullish(),
sni: nullableString,
allow_insecure: nullableBool,
fingerprint: nullableString,
@ -137,8 +147,9 @@ const naive = z.object({
const http = z.object({
type: z.literal('http'),
enable: nullableBool,
port: nullablePort,
security: z.enum(SECURITY.http as any).nullish(),
security: z.enum(SECURITY.http).nullish(),
sni: nullableString,
allow_insecure: nullableBool,
fingerprint: nullableString,
@ -146,9 +157,10 @@ const http = z.object({
const mieru = z.object({
type: z.literal('mieru'),
enable: nullableBool,
port: nullablePort,
multiplex: z.enum(multiplexLevels).nullish(),
transport: z.enum(TRANSPORTS.mieru as any).nullish(),
transport: z.enum(TRANSPORTS.mieru).nullish(),
});
export const protocolApiScheme = z.discriminatedUnion('type', [

View File

@ -14,21 +14,3 @@ export async function generateMLKEM768KeyPair() {
privateKey: toB64Url(new Uint8Array(mlkemPrivateKeyRaw)),
};
}
const test = await generateMLKEM768KeyPair();
console.log('生成的密钥信息:');
console.log('私钥长度:', test.privateKey.length);
console.log('公钥长度:', test.publicKey.length);
console.log(test);
// 从 VLESS 配置字符串中提取的密钥
const extractedKeys = {
decryptionKey:
'B2qLcDHhiztvBaB4BhMCnU-fM-axE4DZowMK9TIvL5qma2M5fVAmFswPdfej2N1SmlJa5ppidC1ksHLVfoEvjw',
encryptionKey:
'FgEI5sTIzBgZS4psemcdGDCRb5JvdDFqzOeVvLJYEmmZFSgxG1SkYxx8DUO-txGqvYdhFruja-ZzmIQoGOCQEMd0RbK4BhYRm4jE96GXTytu7Hi7pYo9-2SEuKC10righ2ceqis0LoggubajmAFvkop6igZfcmEA3MJ9aHpjGiUszDWy0pA99WY7c1ebTom8xQetW2J2OnkrA_UE8Cuy8AhMPvSBQrsFNmBqnttfVlmKzPS3RWBkIpAZIie1XMGk76nDEXgEsBulEhmYO2Mc-oRfirQfGmYfD1ybYBs9gAKgzQixTrkJtOuRU4GjkwQpxuyeVuww8Pin19IzAlVpUdeEJPVlRHwQDNJ__YsZDJB6rSIaY4tM4ysSs3N-1mmYvkVs1WSa0uy14KRheqMIPfsw_KxLBvp2_ZdZeQIrW3dDxgOuxXWip-g78desyONwwkx0bQK-JDcELHEH0TVmTOe4mSqW1fPI6jJI_ZChmQwBxZKpp2RN2xKmw6W3z4ETdUQDTZgePEkXDveneltNHrGT73WJQ7uEs6hwfXwD2vGcuFx6DKybfYAzgWh9t4IM3mBI7OiGqDItigqIDgaBF6LPTXwby3VxgfEVXXqXzMVdc0BL4da1BPGF-lAtvVJtbpBp7_O_JlB1wWajv8eLCpKjRiKGQey7oLZyRROQ3loNFyRDBjoBVSa2etCmFRCV1wegIBqmJRImJQxPsIV_kkIxeWmPfUIik1GpSTtrWkAFCXZAl4oSFiNhLwlmW_g_s_glGeqcZBNAkiw-OlssPESmqLti-bSJPbmoJMNE0poJXCYX27YyPKVyCtJKM5pzOkUBqMIVsxliU4N2IaWHb8uMYKW8U0tQ8aaeR3Bf5ll0fza78aY3lSQw7At21XkN9LhugzWv-_CPGZQpStGCWtJl5dChLPlmZbRddmekp7UEfXAPW6ONyNrFZ9WUvBCwsdmXcChTXwkg-FIMFHpU25c6IwWqyveuZrQmpvZYEQSgyWhsUBMPywI1vqiLfuhnaqBNU9wPbGA0IrG-w9UGpQErl9ssqPdZRjaIbiM-PKKooehp34QzU3ENj5h944gC4yHMkMzOPUaFl8YUWwmkGCsTNnJyq7NLucTOdQSUsLM2QWEkxWk9c6YyQkwx2mUsR1eGmrsbo8BGK6ppbgotpzMjGZfPOQRdHYh0lzGQ28HGetJ97Vei8Vxxl2u4j6CfHTPET4EHZ_uTuPtRIaaMegKOtUgyKqKj4BqsB5tatIECz8N1H_LP5qlRvUxYqrU-JikuRCoAdfl7VFYLLhe_80cny2UoWFpJ1iovprnALDbIIKZ03LG0OXI8dfEolQijO1xhwoUb7Ci3Xma-wKyEWHhSw0e600SRT0RhDuOh5hVg4KVLILUDDuMIJQyiPRBW3qwAMCk1SzCeXvFqbWFU-TQnVoLGNboaygQ6aumgP_B4DBcmEdyVqAMHIOdAPENvLauALKSiBHVjEHgeB7KpVCGsIGOjdCgb4UmKdsxnXBxC7peXspcmGgmHL-VU6KdMhwHwq1mYeNVEzeshb5mWYj5fgysp_e5U--geYKefs5Y',
};
console.log('提取的密钥信息:');
console.log('私钥长度:', extractedKeys.decryptionKey.length);
console.log('公钥长度:', extractedKeys.encryptionKey.length);

View File

@ -364,24 +364,18 @@ export default function ServerForm(props: {
}, [initialValues]);
async function handleSubmit(values: Record<string, any>) {
const filtered = (values?.protocols || []).filter((p: any, index: number) => {
const port = Number(p?.port);
const protocolType = PROTOCOLS[index];
return protocolType && p && Number.isFinite(port) && port > 0 && port <= 65535;
const filteredProtocols = (values?.protocols || []).filter((protocol: any) => {
const port = Number(protocol?.port);
return protocol && Number.isFinite(port) && port > 0 && port <= 65535;
});
if (filtered.length === 0) {
toast.error(t('validation_failed'));
return;
}
const result = {
name: values.name,
country: values.country,
city: values.city,
ratio: Number(values.ratio || 1),
ratio: values.ratio || 1,
address: values.address,
protocols: filtered,
protocols: filteredProtocols,
};
const ok = await onSubmit(result);
@ -507,6 +501,7 @@ export default function ServerForm(props: {
{t('protocol_configurations_desc')}
</p>
</div>
<Accordion
type='single'
collapsible
@ -520,39 +515,45 @@ export default function ServerForm(props: {
PROTOCOLS.findIndex((t) => t === type),
);
const current = (protocolsValues[i] || {}) as Record<string, any>;
const isEnabled = current.port && Number(current.port) > 0;
const fields = PROTOCOL_FIELDS[type] || [];
return (
<AccordionItem key={type} value={type} className='mb-2 rounded-lg border'>
<AccordionTrigger className='px-4 py-3 hover:no-underline'>
<div className='flex w-full items-center justify-between'>
<div className='flex flex-col items-start'>
<div className='flex items-center gap-2'>
<div className='flex flex-col items-start gap-1'>
<div className='flex items-center gap-1'>
<span className='font-medium capitalize'>{type}</span>
</div>
<span
className={cn(
'text-muted-foreground text-xs',
isEnabled && 'text-green-500',
{current.transport && (
<Badge variant='secondary' className='text-xs'>
{current.transport.toUpperCase()}
</Badge>
)}
>
{isEnabled ? t('enabled') : t('disabled')}
</span>
</div>
<div className='mr-2 flex items-center gap-1'>
{current.transport && (
<Badge variant='secondary' className='text-xs'>
{current.transport.toUpperCase()}
</Badge>
)}
{current.security && current.security !== 'none' && (
<Badge variant='outline' className='text-xs'>
{current.security.toUpperCase()}
</Badge>
)}
{current.port && <Badge className='text-xs'>{current.port}</Badge>}
{current.security && current.security !== 'none' && (
<Badge variant='outline' className='text-xs'>
{current.security.toUpperCase()}
</Badge>
)}
{current.port && <Badge className='text-xs'>{current.port}</Badge>}
</div>
<div className='flex items-center gap-1'>
<span
className={cn(
'text-xs',
current.enable ? 'text-green-500' : 'text-muted-foreground',
)}
>
{current.enable ? t('enabled') : t('disabled')}
</span>
</div>
</div>
<Switch
className='mr-2'
checked={!!current.enable}
onCheckedChange={(checked) => {
form.setValue(`protocols.${i}.enable`, checked);
}}
onClick={(e) => e.stopPropagation()}
/>
</div>
</AccordionTrigger>
<AccordionContent className='px-4 pb-4 pt-0'>
@ -621,7 +622,8 @@ export default function ServerForm(props: {
return false;
})}
>
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />} {t('confirm')}
{loading && <Icon icon='mdi:loading' className='mr-2 animate-spin' />}
{t('confirm')}
</Button>
</SheetFooter>
</SheetContent>

View File

@ -1,5 +1,5 @@
// @ts-ignore
// API 更新时间:
// API 唯一标识:
import * as ads from './ads';

View File

@ -1496,6 +1496,7 @@ declare namespace API {
type Protocol = {
type: string;
port: number;
enable: boolean;
security?: string;
sni?: string;
allow_insecure?: boolean;
@ -1519,10 +1520,6 @@ declare namespace API {
reduce_rtt?: boolean;
udp_relay_mode?: string;
congestion_controller?: string;
/** obfs, v2ray-plugin, simple-obfs */
plugin?: string;
/** plugin options, eg: obfs=http;obfs-host=www.bing.com */
plugin_options?: string;
/** mux, eg: off/low/medium/high */
multiplex?: string;
/** padding scheme */
@ -1531,6 +1528,32 @@ declare namespace API {
up_mbps?: number;
/** download speed limit */
down_mbps?: number;
/** obfs, 'none', 'http', 'tls' */
obfs?: string;
/** obfs host */
obfs_host?: string;
/** obfs path */
obfs_path?: string;
/** xhttp mode */
xhttp_mode?: string;
/** xhttp extra path */
xhttp_extra?: string;
/** encryption'none', 'mlkem768x25519plus' */
encryption?: string;
/** encryption mode'native', 'xorpub', 'random' */
encryption_mode?: string;
/** encryption rtt'0rtt', '1rtt' */
encryption_rtt?: string;
/** encryption ticket */
encryption_ticket?: string;
/** encryption server padding */
encryption_server_padding?: string;
/** encryption private key */
encryption_private_key?: string;
/** encryption client padding */
encryption_client_padding?: string;
/** encryption password */
encryption_password?: string;
};
type PubilcRegisterConfig = {

View File

@ -1,5 +1,5 @@
// @ts-ignore
// API 更新时间:
// API 唯一标识:
import * as auth from './auth';

View File

@ -504,6 +504,7 @@ declare namespace API {
type Protocol = {
type: string;
port: number;
enable: boolean;
security?: string;
sni?: string;
allow_insecure?: boolean;
@ -527,10 +528,6 @@ declare namespace API {
reduce_rtt?: boolean;
udp_relay_mode?: string;
congestion_controller?: string;
/** obfs, v2ray-plugin, simple-obfs */
plugin?: string;
/** plugin options, eg: obfs=http;obfs-host=www.bing.com */
plugin_options?: string;
/** mux, eg: off/low/medium/high */
multiplex?: string;
/** padding scheme */
@ -539,6 +536,32 @@ declare namespace API {
up_mbps?: number;
/** download speed limit */
down_mbps?: number;
/** obfs, 'none', 'http', 'tls' */
obfs?: string;
/** obfs host */
obfs_host?: string;
/** obfs path */
obfs_path?: string;
/** xhttp mode */
xhttp_mode?: string;
/** xhttp extra path */
xhttp_extra?: string;
/** encryption'none', 'mlkem768x25519plus' */
encryption?: string;
/** encryption mode'native', 'xorpub', 'random' */
encryption_mode?: string;
/** encryption rtt'0rtt', '1rtt' */
encryption_rtt?: string;
/** encryption ticket */
encryption_ticket?: string;
/** encryption server padding */
encryption_server_padding?: string;
/** encryption private key */
encryption_private_key?: string;
/** encryption client padding */
encryption_client_padding?: string;
/** encryption password */
encryption_password?: string;
};
type PubilcRegisterConfig = {

View File

@ -1,5 +1,5 @@
// @ts-ignore
// API 更新时间:
// API 唯一标识:
import * as auth from './auth';

View File

@ -504,6 +504,7 @@ declare namespace API {
type Protocol = {
type: string;
port: number;
enable: boolean;
security?: string;
sni?: string;
allow_insecure?: boolean;
@ -527,10 +528,6 @@ declare namespace API {
reduce_rtt?: boolean;
udp_relay_mode?: string;
congestion_controller?: string;
/** obfs, v2ray-plugin, simple-obfs */
plugin?: string;
/** plugin options, eg: obfs=http;obfs-host=www.bing.com */
plugin_options?: string;
/** mux, eg: off/low/medium/high */
multiplex?: string;
/** padding scheme */
@ -539,6 +536,32 @@ declare namespace API {
up_mbps?: number;
/** download speed limit */
down_mbps?: number;
/** obfs, 'none', 'http', 'tls' */
obfs?: string;
/** obfs host */
obfs_host?: string;
/** obfs path */
obfs_path?: string;
/** xhttp mode */
xhttp_mode?: string;
/** xhttp extra path */
xhttp_extra?: string;
/** encryption'none', 'mlkem768x25519plus' */
encryption?: string;
/** encryption mode'native', 'xorpub', 'random' */
encryption_mode?: string;
/** encryption rtt'0rtt', '1rtt' */
encryption_rtt?: string;
/** encryption ticket */
encryption_ticket?: string;
/** encryption server padding */
encryption_server_padding?: string;
/** encryption private key */
encryption_private_key?: string;
/** encryption client padding */
encryption_client_padding?: string;
/** encryption password */
encryption_password?: string;
};
type PubilcRegisterConfig = {

View File

@ -1,5 +1,5 @@
// @ts-ignore
// API 更新时间:
// API 唯一标识:
import * as announcement from './announcement';

View File

@ -543,6 +543,7 @@ declare namespace API {
type Protocol = {
type: string;
port: number;
enable: boolean;
security?: string;
sni?: string;
allow_insecure?: boolean;
@ -566,10 +567,6 @@ declare namespace API {
reduce_rtt?: boolean;
udp_relay_mode?: string;
congestion_controller?: string;
/** obfs, v2ray-plugin, simple-obfs */
plugin?: string;
/** plugin options, eg: obfs=http;obfs-host=www.bing.com */
plugin_options?: string;
/** mux, eg: off/low/medium/high */
multiplex?: string;
/** padding scheme */
@ -578,6 +575,32 @@ declare namespace API {
up_mbps?: number;
/** download speed limit */
down_mbps?: number;
/** obfs, 'none', 'http', 'tls' */
obfs?: string;
/** obfs host */
obfs_host?: string;
/** obfs path */
obfs_path?: string;
/** xhttp mode */
xhttp_mode?: string;
/** xhttp extra path */
xhttp_extra?: string;
/** encryption'none', 'mlkem768x25519plus' */
encryption?: string;
/** encryption mode'native', 'xorpub', 'random' */
encryption_mode?: string;
/** encryption rtt'0rtt', '1rtt' */
encryption_rtt?: string;
/** encryption ticket */
encryption_ticket?: string;
/** encryption server padding */
encryption_server_padding?: string;
/** encryption private key */
encryption_private_key?: string;
/** encryption client padding */
encryption_client_padding?: string;
/** encryption password */
encryption_password?: string;
};
type PubilcRegisterConfig = {