// 各协议的创建向导表单定义(前端动态渲染) // label / tip / name / desc / scenes / option labels 存放 i18n key, // 在模板中通过 $t() 翻译;placeholder / default / key 等保持原始值。 export const PROTOCOL_META = { wireguard: { name: 'protocols.wireguard.name', desc: 'protocols.wireguard.desc', color: '#c0392b', icon: 'wireguard', scenes: 'protocols.wireguard.scenes', fields: [ { key: 'address', label: 'protocols.wireguard.fields.address.label', placeholder: '10.8.0.1/24', required: true, tip: 'protocols.wireguard.fields.address.tip', group: 'basic' }, { key: 'listen_port', label: 'protocols.wireguard.fields.listen_port.label', type: 'number', default: 51820, group: 'basic' }, { key: 'client_address', label: 'protocols.wireguard.fields.client_address.label', placeholder: '10.8.0.2/32', tip: 'protocols.wireguard.fields.client_address.tip', group: 'basic' }, { key: 'public_endpoint', label: 'protocols.wireguard.fields.public_endpoint.label', placeholder: 'vpn.example.com:51820', tip: 'protocols.wireguard.fields.public_endpoint.tip', group: 'basic' }, { key: 'dns', label: 'protocols.wireguard.fields.dns.label', default: '223.5.5.5', group: 'basic' }, { key: 'allowed_ips', label: 'protocols.wireguard.fields.allowed_ips.label', default: '0.0.0.0/0, ::/0', tip: 'protocols.wireguard.fields.allowed_ips.tip', group: 'routing' }, { key: 'keepalive', label: 'protocols.wireguard.fields.keepalive.label', type: 'number', default: 25, tip: 'protocols.wireguard.fields.keepalive.tip', group: 'advanced' }, { key: 'mtu', label: 'protocols.wireguard.fields.mtu.label', type: 'number', default: 0, tip: 'protocols.wireguard.fields.mtu.tip', group: 'advanced' }, { key: 'enable_nat', label: 'protocols.wireguard.fields.enable_nat.label', type: 'switch', default: false, tip: 'protocols.wireguard.fields.enable_nat.tip', group: 'routing' }, { key: 'egress_interface', label: 'protocols.wireguard.fields.egress_interface.label', placeholder: 'eth0', tip: 'protocols.wireguard.fields.egress_interface.tip', showIf: { enable_nat: true }, group: 'routing' } ] }, ipsec: { name: 'protocols.ipsec.name', desc: 'protocols.ipsec.desc', color: '#1f6fb2', icon: 'ipsec', scenes: 'protocols.ipsec.scenes', fields: [ { key: 'vendor_template', label: 'protocols.ipsec.fields.vendor_template.label', type: 'select', options: [ { value: 'generic', label: 'protocols.ipsec.fields.vendor_template.options.generic' }, { value: 'cisco', label: 'protocols.ipsec.fields.vendor_template.options.cisco' }, { value: 'fortigate', label: 'protocols.ipsec.fields.vendor_template.options.fortigate' }, { value: 'huawei', label: 'protocols.ipsec.fields.vendor_template.options.huawei' }, { value: 'h3c', label: 'protocols.ipsec.fields.vendor_template.options.h3c' } ], default: 'generic', tip: 'protocols.ipsec.fields.vendor_template.tip', group: 'basic' }, { key: 'public_endpoint', label: 'protocols.ipsec.fields.public_endpoint.label', placeholder: '1.2.3.4', required: true, group: 'basic' }, { key: 'remote_gateway', label: 'protocols.ipsec.fields.remote_gateway.label', placeholder: '5.6.7.8', required: true, group: 'basic' }, { key: 'local_subnets', label: 'protocols.ipsec.fields.local_subnets.label', placeholder: '192.168.1.0/24', required: true, tip: 'protocols.ipsec.fields.local_subnets.tip', group: 'routing' }, { key: 'remote_subnets', label: 'protocols.ipsec.fields.remote_subnets.label', placeholder: '10.0.0.0/24', required: true, group: 'routing' }, { key: 'psk', label: 'protocols.ipsec.fields.psk.label', type: 'password', required: true, secret: true, group: 'basic' }, { key: 'ike_version', label: 'protocols.ipsec.fields.ike_version.label', type: 'select', options: [ { value: 'ikev2', label: 'protocols.ipsec.fields.ike_version.options.ikev2' }, { value: 'ikev1', label: 'protocols.ipsec.fields.ike_version.options.ikev1' } ], default: 'ikev2', group: 'crypto' }, { key: 'ike_proposal', label: 'protocols.ipsec.fields.ike_proposal.label', placeholder: 'aes256-sha256-modp2048', tip: 'protocols.ipsec.fields.ike_proposal.tip', group: 'crypto' }, { key: 'esp_proposal', label: 'protocols.ipsec.fields.esp_proposal.label', placeholder: 'aes256-sha256', group: 'crypto' }, { key: 'pfs_group', label: 'protocols.ipsec.fields.pfs_group.label', default: 'modp2048', group: 'crypto' }, { key: 'ike_lifetime', label: 'protocols.ipsec.fields.ike_lifetime.label', type: 'number', default: 86400, group: 'advanced' }, { key: 'local_id', label: 'protocols.ipsec.fields.local_id.label', placeholder: '@vpn-local', group: 'advanced' }, { key: 'remote_id', label: 'protocols.ipsec.fields.remote_id.label', placeholder: '@vpn-remote', group: 'advanced' } ] }, ikev2: { name: 'protocols.ikev2.name', desc: 'protocols.ikev2.desc', color: '#0d7377', icon: 'ikev2', scenes: 'protocols.ikev2.scenes', fields: [ { key: 'public_endpoint', label: 'protocols.ikev2.fields.public_endpoint.label', placeholder: 'vpn.example.com', required: true, group: 'basic' }, { key: 'local_id', label: 'protocols.ikev2.fields.local_id.label', placeholder: '@opsx-ikev2', default: '@opsx-ikev2', tip: 'protocols.ikev2.fields.local_id.tip', group: 'basic' }, { key: 'psk', label: 'protocols.ikev2.fields.psk.label', type: 'password', secret: true, tip: 'protocols.ikev2.fields.psk.tip', group: 'basic' }, { key: 'address_pool', label: 'protocols.ikev2.fields.address_pool.label', default: '10.12.0.0/24', group: 'basic' }, { key: 'dns', label: 'protocols.ikev2.fields.dns.label', default: '223.5.5.5', group: 'basic' }, { key: 'local_ts', label: 'protocols.ikev2.fields.local_ts.label', default: '0.0.0.0/0', tip: 'protocols.ikev2.fields.local_ts.tip', group: 'routing' }, { key: 'ike_proposal', label: 'protocols.ikev2.fields.ike_proposal.label', default: 'aes256-sha256-modp2048', group: 'crypto' }, { key: 'esp_proposal', label: 'protocols.ikev2.fields.esp_proposal.label', default: 'aes256-sha256', group: 'crypto' } ] }, l2tp: { name: 'protocols.l2tp.name', desc: 'protocols.l2tp.desc', color: '#5a8a3c', icon: 'l2tp', scenes: 'protocols.l2tp.scenes', fields: [ { key: 'public_endpoint', label: 'protocols.l2tp.fields.public_endpoint.label', placeholder: '1.2.3.4', required: true, group: 'basic' }, { key: 'psk', label: 'protocols.l2tp.fields.psk.label', type: 'password', secret: true, tip: 'protocols.l2tp.fields.psk.tip', group: 'basic' }, { key: 'ip_range', label: 'protocols.l2tp.fields.ip_range.label', default: '10.9.0.100-10.9.0.200', group: 'routing' }, { key: 'local_ip', label: 'protocols.l2tp.fields.local_ip.label', default: '10.9.0.1', group: 'routing' }, { key: 'dns', label: 'protocols.l2tp.fields.dns.label', default: '223.5.5.5', group: 'routing' } ] }, gre: { name: 'protocols.gre.name', desc: 'protocols.gre.desc', color: '#357a8b', icon: 'gre', scenes: 'protocols.gre.scenes', fields: [ { key: 'local_endpoint', label: 'protocols.gre.fields.local_endpoint.label', placeholder: '134.175.167.191', required: true, group: 'basic' }, { key: 'remote_endpoint', label: 'protocols.gre.fields.remote_endpoint.label', placeholder: '203.0.113.10', required: true, group: 'basic' }, { key: 'local_tunnel_ip', label: 'protocols.gre.fields.local_tunnel_ip.label', placeholder: '10.255.0.1/30', required: true, group: 'basic' }, { key: 'remote_tunnel_ip', label: 'protocols.gre.fields.remote_tunnel_ip.label', placeholder: '10.255.0.2/30', required: true, group: 'basic' }, { key: 'remote_subnet', label: 'protocols.gre.fields.remote_subnet.label', placeholder: '192.168.10.0/24', tip: 'protocols.gre.fields.remote_subnet.tip', group: 'routing' }, { key: 'enable_nat', label: 'protocols.gre.fields.enable_nat.label', type: 'switch', default: false, tip: 'protocols.gre.fields.enable_nat.tip', group: 'routing' }, { key: 'outbound_interface', label: 'protocols.gre.fields.outbound_interface.label', placeholder: 'eth0', showIf: { enable_nat: true }, group: 'routing' }, { key: 'ttl', label: 'protocols.gre.fields.ttl.label', type: 'number', default: 255, group: 'advanced' }, { key: 'mtu', label: 'protocols.gre.fields.mtu.label', type: 'number', default: 1476, tip: 'protocols.gre.fields.mtu.tip', group: 'advanced' } ] }, frp: { name: 'protocols.frp.name', desc: 'protocols.frp.desc', color: '#c0762b', icon: 'frp', scenes: 'protocols.frp.scenes', fields: [ { key: 'mode', label: 'protocols.frp.fields.mode.label', type: 'select', options: [ { value: 'server', label: 'protocols.frp.fields.mode.options.server' }, { value: 'client', label: 'protocols.frp.fields.mode.options.client' } ], default: 'server', tip: 'protocols.frp.fields.mode.tip', group: 'basic' }, { key: 'bind_port', label: 'protocols.frp.fields.bind_port.label', type: 'number', default: 7000, showIf: { mode: 'server' }, group: 'basic' }, { key: 'public_endpoint', label: 'protocols.frp.fields.public_endpoint.label', placeholder: '1.2.3.4', showIf: { mode: 'server' }, group: 'basic' }, { key: 'dashboard_port', label: 'protocols.frp.fields.dashboard_port.label', type: 'number', default: 7500, showIf: { mode: 'server' }, group: 'advanced' }, { key: 'dashboard_user', label: 'protocols.frp.fields.dashboard_user.label', default: 'admin', showIf: { mode: 'server' }, group: 'advanced' }, { key: 'dashboard_password', label: 'protocols.frp.fields.dashboard_password.label', type: 'password', secret: true, showIf: { mode: 'server' }, tip: 'protocols.frp.fields.dashboard_password.tip', group: 'advanced' }, { key: 'vhost_http_port', label: 'protocols.frp.fields.vhost_http_port.label', type: 'number', default: 0, showIf: { mode: 'server' }, tip: 'protocols.frp.fields.vhost_http_port.tip', group: 'advanced' }, { key: 'vhost_https_port', label: 'protocols.frp.fields.vhost_https_port.label', type: 'number', default: 0, showIf: { mode: 'server' }, tip: 'protocols.frp.fields.vhost_https_port.tip', group: 'advanced' }, { key: 'allow_ports', label: 'protocols.frp.fields.allow_ports.label', placeholder: '6000-6100,7001', showIf: { mode: 'server' }, tip: 'protocols.frp.fields.allow_ports.tip', group: 'advanced' }, { key: 'server_addr', label: 'protocols.frp.fields.server_addr.label', placeholder: '1.2.3.4', showIf: { mode: 'client' }, group: 'basic' }, { key: 'server_port', label: 'protocols.frp.fields.server_port.label', type: 'number', default: 7000, showIf: { mode: 'client' }, group: 'basic' }, { key: 'token', label: 'protocols.frp.fields.token.label', type: 'password', secret: true, tip: 'protocols.frp.fields.token.tip', group: 'basic' }, { key: 'proxy_name', label: 'protocols.frp.fields.proxy_name.label', placeholder: 'ssh', default: 'ssh', group: 'basic' }, { key: 'proxy_type', label: 'protocols.frp.fields.proxy_type.label', type: 'select', options: [ { value: 'tcp', label: 'protocols.frp.fields.proxy_type.options.tcp' }, { value: 'udp', label: 'protocols.frp.fields.proxy_type.options.udp' }, { value: 'http', label: 'protocols.frp.fields.proxy_type.options.http' }, { value: 'https', label: 'protocols.frp.fields.proxy_type.options.https' }, { value: 'stcp', label: 'protocols.frp.fields.proxy_type.options.stcp' }, { value: 'xtcp', label: 'protocols.frp.fields.proxy_type.options.xtcp' } ], default: 'tcp', group: 'basic' }, { key: 'local_ip', label: 'protocols.frp.fields.local_ip.label', default: '127.0.0.1', group: 'basic' }, { key: 'local_port', label: 'protocols.frp.fields.local_port.label', type: 'number', default: 22, group: 'basic' }, { key: 'remote_port', label: 'protocols.frp.fields.remote_port.label', type: 'number', default: 6000, showIf: { proxy_type: ['tcp', 'udp'] }, group: 'basic' }, { key: 'custom_domains', label: 'protocols.frp.fields.custom_domains.label', placeholder: 'app.example.com', showIf: { proxy_type: ['http', 'https'] }, tip: 'protocols.frp.fields.custom_domains.tip', group: 'basic' }, { key: 'secret_key', label: 'protocols.frp.fields.secret_key.label', type: 'password', secret: true, showIf: { proxy_type: ['stcp', 'xtcp'] }, tip: 'protocols.frp.fields.secret_key.tip', group: 'basic' } ] }, openvpn: { name: 'protocols.openvpn.name', desc: 'protocols.openvpn.desc', color: '#e07b39', icon: 'openvpn', scenes: 'protocols.openvpn.scenes', fields: [ { key: 'public_endpoint', label: 'protocols.openvpn.fields.public_endpoint.label', placeholder: 'vpn.example.com', required: true }, { key: 'port', label: 'protocols.openvpn.fields.port.label', type: 'number', default: 1194 }, { key: 'proto', label: 'protocols.openvpn.fields.proto.label', type: 'select', options: [ { value: 'udp', label: 'protocols.openvpn.fields.proto.options.udp' }, { value: 'tcp-server', label: 'protocols.openvpn.fields.proto.options.tcp-server' } ], default: 'tcp-server', tip: 'protocols.openvpn.fields.proto.tip' }, { key: 'subnet', label: 'protocols.openvpn.fields.subnet.label', default: '10.10.0.0 255.255.255.0', tip: 'protocols.openvpn.fields.subnet.tip' }, { key: 'cipher', label: 'protocols.openvpn.fields.cipher.label', type: 'select', options: [ { value: 'AES-256-GCM', label: 'protocols.openvpn.fields.cipher.options.AES-256-GCM' }, { value: 'AES-128-GCM', label: 'protocols.openvpn.fields.cipher.options.AES-128-GCM' }, { value: 'AES-256-CBC', label: 'protocols.openvpn.fields.cipher.options.AES-256-CBC' } ], default: 'AES-256-GCM' }, { key: 'auth_mode', label: 'protocols.openvpn.fields.auth_mode.label', type: 'select', options: [ { value: 'certificate', label: 'protocols.openvpn.fields.auth_mode.options.certificate' }, { value: 'password', label: 'protocols.openvpn.fields.auth_mode.options.password' }, { value: 'certificate+password', label: 'protocols.openvpn.fields.auth_mode.options.certificate+password' }, { value: 'oidc', label: 'protocols.openvpn.fields.auth_mode.options.oidc' } ], default: 'password', tip: 'protocols.openvpn.fields.auth_mode.tip' }, { key: 'mfa_mode', label: 'protocols.openvpn.fields.mfa_mode.label', type: 'select', options: [ { value: 'off', label: 'protocols.openvpn.fields.mfa_mode.options.off' }, { value: 'optional', label: 'protocols.openvpn.fields.mfa_mode.options.optional' }, { value: 'required', label: 'protocols.openvpn.fields.mfa_mode.options.required' } ], default: 'off', tip: 'protocols.openvpn.fields.mfa_mode.tip', showIf: { auth_mode: ['certificate', 'password', 'certificate+password'] } }, { key: 'otp_slop', label: 'protocols.openvpn.fields.otp_slop.label', type: 'number', default: 90, showIf: { auth_mode: ['password', 'certificate+password'] } }, { key: 'otp_max_failures', label: 'protocols.openvpn.fields.otp_max_failures.label', type: 'number', default: 5, showIf: { auth_mode: ['password', 'certificate+password'] } }, { key: 'otp_lockout_sec', label: 'protocols.openvpn.fields.otp_lockout_sec.label', type: 'number', default: 300, showIf: { auth_mode: ['password', 'certificate+password'] } }, { key: 'otp_disallow_reuse', label: 'protocols.openvpn.fields.otp_disallow_reuse.label', type: 'switch', default: true, showIf: { auth_mode: ['password', 'certificate+password'] } }, { key: 'dns', label: 'protocols.openvpn.fields.dns.label', default: '223.5.5.5' }, { key: 'redirect_gateway', label: 'protocols.openvpn.fields.redirect_gateway.label', type: 'switch', default: true, tip: 'protocols.openvpn.fields.redirect_gateway.tip' }, { key: 'push_routes', label: 'protocols.openvpn.fields.push_routes.label', placeholder: '192.168.0.0/16,10.0.0.0/8', tip: 'protocols.openvpn.fields.push_routes.tip' }, { key: 'enable_nat', label: 'protocols.openvpn.fields.enable_nat.label', type: 'switch', default: true }, { key: 'max_clients', label: 'protocols.openvpn.fields.max_clients.label', type: 'number', default: 1000, tip: 'protocols.openvpn.fields.max_clients.tip' }, { key: 'keepalive_interval', label: 'protocols.openvpn.fields.keepalive_interval.label', type: 'number', default: 5, tip: 'protocols.openvpn.fields.keepalive_interval.tip' }, { key: 'keepalive_timeout', label: 'protocols.openvpn.fields.keepalive_timeout.label', type: 'number', default: 30 }, { key: 'tun_mtu', label: 'protocols.openvpn.fields.tun_mtu.label', type: 'number', default: 1500, tip: 'protocols.openvpn.fields.tun_mtu.tip' }, { key: 'tun_mtu_extra', label: 'protocols.openvpn.fields.tun_mtu_extra.label', type: 'number', default: 32 }, { key: 'mssfix', label: 'protocols.openvpn.fields.mssfix.label', type: 'number', default: 0, tip: 'protocols.openvpn.fields.mssfix.tip' }, { key: 'duplicate_cn', label: 'protocols.openvpn.fields.duplicate_cn.label', type: 'switch', default: false, tip: 'protocols.openvpn.fields.duplicate_cn.tip' }, { key: 'reneg_sec', label: 'protocols.openvpn.fields.reneg_sec.label', type: 'number', default: 0, tip: 'protocols.openvpn.fields.reneg_sec.tip' }, { key: 'run_as_user', label: 'protocols.openvpn.fields.run_as_user.label', placeholder: 'openvpn', tip: 'protocols.openvpn.fields.run_as_user.tip' }, { key: 'run_as_group', label: 'protocols.openvpn.fields.run_as_group.label', placeholder: 'openvpn', tip: 'protocols.openvpn.fields.run_as_group.tip' } ] } } // 自定义协议插件的默认表单(插件参数完全自由) export const CUSTOM_FIELDS = [ { key: 'endpoint', label: 'protocols.custom.fields.endpoint.label', placeholder: 'host:port' }, { key: 'token', label: 'protocols.custom.fields.token.label', type: 'password', secret: true }, { key: 'extra', label: 'protocols.custom.fields.extra.label', placeholder: '{"key":"value"}' } ] export const PROTOCOL_COLORS = { wireguard: '#c0392b', ipsec: '#1f6fb2', ikev2: '#0d7377', l2tp: '#4a8a2c', gre: '#357a8b', frp: '#b8651b', openvpn: '#cc6529' } export function protocolDisplay(t) { if (t.startsWith('custom:')) return t.slice(7) return PROTOCOL_META[t]?.name || t } export function protocolColor(t) { if (t.startsWith('custom:')) return '#7b5ea7' return PROTOCOL_COLORS[t] || '#606266' } /** 解析 select 的 options(兼容字符串与 {value,label}) */ export function optionValue(o) { return typeof o === 'object' && o !== null ? o.value : o } export function optionLabel(o) { return typeof o === 'object' && o !== null ? (o.label || o.value) : o }