feat: 后端限速实现 + 前端i18n全面国际化 + 安全与代码质量修复
后端: - trafficmgr: 实现 tc htb 限速(ApplyRateLimit/RemoveRateLimit),自动推导接口名 - 各协议服务: 代码质量改进与错误处理增强 前端: - protocols.js: 170个硬编码中文字符串全部转为 i18n key,中英文双语翻译 - 提取 fmtBytes() 到 utils/format.js 公共模块(消除 4 处重复) - router.js: 添加路由级权限守卫,非管理员无法直接 URL 访问管理页 - Tunnels.vue: SSE 日志流改用 fetch+ReadableStream,token 放 Authorization header - VPNUsers.vue: 修复 catch 块中文硬编码 fallback - 新增 TaskProgress 组件、taskmgr 后端任务管理
This commit is contained in:
1 parent
021d012478
commit
91974fc30f
26 files changed
+1977
-377
No files matched your search
+138
-136
@@ -1,184 +1,186 @@
|
||||
// 各协议的创建向导表单定义(前端动态渲染)
|
||||
// label / tip / name / desc / scenes / option labels 存放 i18n key,
|
||||
// 在模板中通过 $t() 翻译;placeholder / default / key 等保持原始值。
|
||||
export const PROTOCOL_META = {
|
||||
wireguard: {
|
||||
name: 'WireGuard',
|
||||
desc: '性能最好的现代 VPN,内核级实现,漫游友好',
|
||||
name: 'protocols.wireguard.name',
|
||||
desc: 'protocols.wireguard.desc',
|
||||
color: '#c0392b',
|
||||
icon: 'wireguard',
|
||||
scenes: '内部接入 / 移动办公',
|
||||
scenes: 'protocols.wireguard.scenes',
|
||||
fields: [
|
||||
{ key: 'address', label: '服务端 VPN 网段地址', placeholder: '10.8.0.1/24', required: true, tip: '服务端在 VPN 网段中的地址(CIDR)' },
|
||||
{ key: 'listen_port', label: '监听端口', type: 'number', default: 51820 },
|
||||
{ key: 'client_address', label: '首个客户端地址', placeholder: '10.8.0.2/32', tip: '创建后可在详情中继续添加 Peer' },
|
||||
{ key: 'public_endpoint', label: '公网接入点', placeholder: 'vpn.example.com:51820', tip: '客户端连接用,公网 IP:端口' },
|
||||
{ key: 'dns', label: 'DNS', default: '223.5.5.5' },
|
||||
{ key: 'allowed_ips', label: '客户端 AllowedIPs', default: '0.0.0.0/0, ::/0', tip: '全流量代理用 0.0.0.0/0;仅内网填内网网段' },
|
||||
{ key: 'keepalive', label: 'Keepalive(秒)', type: 'number', default: 25, tip: 'NAT 后客户端建议 15–25' },
|
||||
{ key: 'mtu', label: 'MTU', type: 'number', default: 0, tip: '0 表示默认;跨公网常见 1280–1420' },
|
||||
{ key: 'enable_nat', label: '启用 NAT 出网', type: 'switch', default: false, tip: '客户端需访问公网/其它网段时开启' },
|
||||
{ key: 'egress_interface', label: 'NAT 出口网卡', placeholder: 'eth0', tip: '留空则自动探测默认路由网卡', showIf: { enable_nat: true } }
|
||||
{ key: 'address', label: 'protocols.wireguard.fields.address.label', placeholder: '10.8.0.1/24', required: true, tip: 'protocols.wireguard.fields.address.tip' },
|
||||
{ key: 'listen_port', label: 'protocols.wireguard.fields.listen_port.label', type: 'number', default: 51820 },
|
||||
{ key: 'client_address', label: 'protocols.wireguard.fields.client_address.label', placeholder: '10.8.0.2/32', tip: 'protocols.wireguard.fields.client_address.tip' },
|
||||
{ key: 'public_endpoint', label: 'protocols.wireguard.fields.public_endpoint.label', placeholder: 'vpn.example.com:51820', tip: 'protocols.wireguard.fields.public_endpoint.tip' },
|
||||
{ key: 'dns', label: 'protocols.wireguard.fields.dns.label', default: '223.5.5.5' },
|
||||
{ key: 'allowed_ips', label: 'protocols.wireguard.fields.allowed_ips.label', default: '0.0.0.0/0, ::/0', tip: 'protocols.wireguard.fields.allowed_ips.tip' },
|
||||
{ key: 'keepalive', label: 'protocols.wireguard.fields.keepalive.label', type: 'number', default: 25, tip: 'protocols.wireguard.fields.keepalive.tip' },
|
||||
{ key: 'mtu', label: 'protocols.wireguard.fields.mtu.label', type: 'number', default: 0, tip: 'protocols.wireguard.fields.mtu.tip' },
|
||||
{ key: 'enable_nat', label: 'protocols.wireguard.fields.enable_nat.label', type: 'switch', default: false, tip: 'protocols.wireguard.fields.enable_nat.tip' },
|
||||
{ key: 'egress_interface', label: 'protocols.wireguard.fields.egress_interface.label', placeholder: 'eth0', tip: 'protocols.wireguard.fields.egress_interface.tip', showIf: { enable_nat: true } }
|
||||
]
|
||||
},
|
||||
ipsec: {
|
||||
name: 'IPSec 站点互联',
|
||||
desc: '与第三方设备(Cisco/华为/飞塔等)做站点到站点对接',
|
||||
name: 'protocols.ipsec.name',
|
||||
desc: 'protocols.ipsec.desc',
|
||||
color: '#1f6fb2',
|
||||
icon: 'ipsec',
|
||||
scenes: '第三方对接 / 站点互联',
|
||||
scenes: 'protocols.ipsec.scenes',
|
||||
fields: [
|
||||
{ key: 'vendor_template', label: '厂商模板', type: 'select', options: [
|
||||
{ value: 'generic', label: '通用标准(推荐)' },
|
||||
{ value: 'cisco', label: 'Cisco ISR/ASR' },
|
||||
{ value: 'fortigate', label: 'FortiGate' },
|
||||
{ value: 'huawei', label: '华为 USG/AR' },
|
||||
{ value: 'h3c', label: 'H3C' }
|
||||
], default: 'generic', tip: '自动预填 Phase1/Phase2 提议,仍可手动改' },
|
||||
{ key: 'public_endpoint', label: '本端公网 IP', placeholder: '1.2.3.4', required: true },
|
||||
{ key: 'remote_gateway', label: '对端网关地址', placeholder: '5.6.7.8', required: true },
|
||||
{ key: 'local_subnets', label: '本端网段', placeholder: '192.168.1.0/24', required: true, tip: '多个网段用逗号分隔' },
|
||||
{ key: 'remote_subnets', label: '对端网段', placeholder: '10.0.0.0/24', required: true },
|
||||
{ key: 'psk', label: '预共享密钥 PSK', type: 'password', required: true, secret: true },
|
||||
{ key: 'ike_version', label: 'IKE 版本', type: 'select', options: [
|
||||
{ value: 'ikev2', label: 'IKEv2' },
|
||||
{ value: 'ikev1', label: 'IKEv1' }
|
||||
{ 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' },
|
||||
{ key: 'public_endpoint', label: 'protocols.ipsec.fields.public_endpoint.label', placeholder: '1.2.3.4', required: true },
|
||||
{ key: 'remote_gateway', label: 'protocols.ipsec.fields.remote_gateway.label', placeholder: '5.6.7.8', required: true },
|
||||
{ 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' },
|
||||
{ key: 'remote_subnets', label: 'protocols.ipsec.fields.remote_subnets.label', placeholder: '10.0.0.0/24', required: true },
|
||||
{ key: 'psk', label: 'protocols.ipsec.fields.psk.label', type: 'password', required: true, secret: true },
|
||||
{ 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' },
|
||||
{ key: 'ike_proposal', label: 'Phase1 提议', placeholder: 'aes256-sha256-modp2048', tip: '加密-认证-DH组,需与对端一致' },
|
||||
{ key: 'esp_proposal', label: 'Phase2 提议', placeholder: 'aes256-sha256' },
|
||||
{ key: 'pfs_group', label: 'PFS DH 组', default: 'modp2048' },
|
||||
{ key: 'ike_lifetime', label: 'IKE 生存期(秒)', type: 'number', default: 86400 },
|
||||
{ key: 'local_id', label: '本端标识 ID', placeholder: '@vpn-local' },
|
||||
{ key: 'remote_id', label: '对端标识 ID', placeholder: '@vpn-remote' }
|
||||
{ key: 'ike_proposal', label: 'protocols.ipsec.fields.ike_proposal.label', placeholder: 'aes256-sha256-modp2048', tip: 'protocols.ipsec.fields.ike_proposal.tip' },
|
||||
{ key: 'esp_proposal', label: 'protocols.ipsec.fields.esp_proposal.label', placeholder: 'aes256-sha256' },
|
||||
{ key: 'pfs_group', label: 'protocols.ipsec.fields.pfs_group.label', default: 'modp2048' },
|
||||
{ key: 'ike_lifetime', label: 'protocols.ipsec.fields.ike_lifetime.label', type: 'number', default: 86400 },
|
||||
{ key: 'local_id', label: 'protocols.ipsec.fields.local_id.label', placeholder: '@vpn-local' },
|
||||
{ key: 'remote_id', label: 'protocols.ipsec.fields.remote_id.label', placeholder: '@vpn-remote' }
|
||||
]
|
||||
},
|
||||
ikev2: {
|
||||
name: 'IKEv2 远程接入',
|
||||
desc: '手机/笔记本原生拨号进内网,比 L2TP 更现代',
|
||||
name: 'protocols.ikev2.name',
|
||||
desc: 'protocols.ikev2.desc',
|
||||
color: '#0d7377',
|
||||
icon: 'ikev2',
|
||||
scenes: '员工远程办公 / 原生 VPN',
|
||||
scenes: 'protocols.ikev2.scenes',
|
||||
fields: [
|
||||
{ key: 'public_endpoint', label: '服务器公网地址', placeholder: 'vpn.example.com', required: true },
|
||||
{ key: 'local_id', label: '服务器 ID / 远程 ID', placeholder: '@opsx-ikev2', default: '@opsx-ikev2', tip: '客户端「远程 ID」与此一致' },
|
||||
{ key: 'psk', label: '机器认证 PSK', type: 'password', secret: true, tip: '留空自动生成;iOS/Android 共享密钥' },
|
||||
{ key: 'username', label: '默认拨号用户', default: 'vpnuser' },
|
||||
{ key: 'password', label: '默认拨号密码', type: 'password', secret: true, tip: '留空自动生成;更多账号在拨号用户页添加' },
|
||||
{ key: 'address_pool', label: '客户端地址池', default: '10.12.0.0/24' },
|
||||
{ key: 'dns', label: '下发 DNS', default: '223.5.5.5' },
|
||||
{ key: 'local_ts', label: '放行网段', default: '0.0.0.0/0', tip: '0.0.0.0/0 为全流量;可改为内网 CIDR' },
|
||||
{ key: 'ike_proposal', label: 'IKE 提议', default: 'aes256-sha256-modp2048' },
|
||||
{ key: 'esp_proposal', label: 'ESP 提议', default: 'aes256-sha256' }
|
||||
{ key: 'public_endpoint', label: 'protocols.ikev2.fields.public_endpoint.label', placeholder: 'vpn.example.com', required: true },
|
||||
{ key: 'local_id', label: 'protocols.ikev2.fields.local_id.label', placeholder: '@opsx-ikev2', default: '@opsx-ikev2', tip: 'protocols.ikev2.fields.local_id.tip' },
|
||||
{ key: 'psk', label: 'protocols.ikev2.fields.psk.label', type: 'password', secret: true, tip: 'protocols.ikev2.fields.psk.tip' },
|
||||
{ key: 'username', label: 'protocols.ikev2.fields.username.label', default: 'vpnuser' },
|
||||
{ key: 'password', label: 'protocols.ikev2.fields.password.label', type: 'password', secret: true, tip: 'protocols.ikev2.fields.password.tip' },
|
||||
{ key: 'address_pool', label: 'protocols.ikev2.fields.address_pool.label', default: '10.12.0.0/24' },
|
||||
{ key: 'dns', label: 'protocols.ikev2.fields.dns.label', default: '223.5.5.5' },
|
||||
{ key: 'local_ts', label: 'protocols.ikev2.fields.local_ts.label', default: '0.0.0.0/0', tip: 'protocols.ikev2.fields.local_ts.tip' },
|
||||
{ key: 'ike_proposal', label: 'protocols.ikev2.fields.ike_proposal.label', default: 'aes256-sha256-modp2048' },
|
||||
{ key: 'esp_proposal', label: 'protocols.ikev2.fields.esp_proposal.label', default: 'aes256-sha256' }
|
||||
]
|
||||
},
|
||||
l2tp: {
|
||||
name: 'L2TP/IPSec',
|
||||
desc: '兼容性最好,手机/老设备/路由器原生支持',
|
||||
name: 'protocols.l2tp.name',
|
||||
desc: 'protocols.l2tp.desc',
|
||||
color: '#5a8a3c',
|
||||
icon: 'l2tp',
|
||||
scenes: '移动设备 / 老设备兼容',
|
||||
scenes: 'protocols.l2tp.scenes',
|
||||
fields: [
|
||||
{ key: 'public_endpoint', label: '服务器公网 IP', placeholder: '1.2.3.4', required: true },
|
||||
{ key: 'psk', label: 'IPSec 预共享密钥', type: 'password', required: true, secret: true },
|
||||
{ key: 'username', label: '默认拨号用户名', default: 'vpnuser', tip: '可在「VPN 拨号用户」为本隧道添加更多账号' },
|
||||
{ key: 'password', label: '默认拨号密码', type: 'password', secret: true, tip: '若只使用拨号用户表可留空(创建时需至少有一种)' },
|
||||
{ key: 'ip_range', label: '客户端地址池', default: '10.9.0.100-10.9.0.200' },
|
||||
{ key: 'local_ip', label: '服务端隧道地址', default: '10.9.0.1' },
|
||||
{ key: 'dns', label: '下发 DNS', default: '223.5.5.5' }
|
||||
{ key: 'public_endpoint', label: 'protocols.l2tp.fields.public_endpoint.label', placeholder: '1.2.3.4', required: true },
|
||||
{ key: 'psk', label: 'protocols.l2tp.fields.psk.label', type: 'password', required: true, secret: true },
|
||||
{ key: 'username', label: 'protocols.l2tp.fields.username.label', default: 'vpnuser', tip: 'protocols.l2tp.fields.username.tip' },
|
||||
{ key: 'password', label: 'protocols.l2tp.fields.password.label', type: 'password', secret: true, tip: 'protocols.l2tp.fields.password.tip' },
|
||||
{ key: 'ip_range', label: 'protocols.l2tp.fields.ip_range.label', default: '10.9.0.100-10.9.0.200' },
|
||||
{ key: 'local_ip', label: 'protocols.l2tp.fields.local_ip.label', default: '10.9.0.1' },
|
||||
{ key: 'dns', label: 'protocols.l2tp.fields.dns.label', default: '223.5.5.5' }
|
||||
]
|
||||
},
|
||||
frp: {
|
||||
name: 'FRP 内网穿透',
|
||||
desc: '国内刚需,TCP/UDP/HTTP 端口映射与反向代理',
|
||||
name: 'protocols.frp.name',
|
||||
desc: 'protocols.frp.desc',
|
||||
color: '#c0762b',
|
||||
icon: 'frp',
|
||||
scenes: '内网穿透 / 端口映射',
|
||||
scenes: 'protocols.frp.scenes',
|
||||
fields: [
|
||||
{ key: 'mode', label: '运行模式', type: 'select', options: [
|
||||
{ value: 'server', label: 'server (frps 公网侧)' },
|
||||
{ value: 'client', label: 'client (frpc 内网侧)' }
|
||||
], default: 'server', tip: 'server=frps(有公网),client=frpc(内网侧)' },
|
||||
{ key: 'bind_port', label: '绑定端口(server)', type: 'number', default: 7000, showIf: { mode: 'server' } },
|
||||
{ key: 'public_endpoint', label: '公网地址(server)', placeholder: '1.2.3.4', showIf: { mode: 'server' } },
|
||||
{ key: 'dashboard_port', label: '管理面板端口(server)', type: 'number', default: 7500, showIf: { mode: 'server' } },
|
||||
{ key: 'dashboard_user', label: '管理面板账号(server)', default: 'admin', showIf: { mode: 'server' } },
|
||||
{ key: 'dashboard_password', label: '管理面板密码(server)', type: 'password', secret: true, showIf: { mode: 'server' }, tip: '留空时自动生成强随机密码;编辑时留空保持原密码' },
|
||||
{ key: 'vhost_http_port', label: 'HTTP 虚拟主机端口', type: 'number', default: 0, showIf: { mode: 'server' }, tip: '0 表示不启用;HTTP 代理需 >0' },
|
||||
{ key: 'vhost_https_port', label: 'HTTPS 虚拟主机端口', type: 'number', default: 0, showIf: { mode: 'server' }, tip: '0 表示不启用' },
|
||||
{ key: 'allow_ports', label: '允许映射端口范围', placeholder: '6000-6100,7001', showIf: { mode: 'server' }, tip: '限制 frpc 可申请的 remotePort' },
|
||||
{ key: 'server_addr', label: 'frps 地址(client)', placeholder: '1.2.3.4', showIf: { mode: 'client' } },
|
||||
{ key: 'server_port', label: 'frps 端口(client)', type: 'number', default: 7000, showIf: { mode: 'client' } },
|
||||
{ key: 'token', label: '认证 Token', type: 'password', secret: true, tip: '留空自动生成' },
|
||||
{ key: 'proxy_name', label: '代理名称', placeholder: 'ssh', default: 'ssh' },
|
||||
{ key: 'proxy_type', label: '代理类型', type: 'select', options: [
|
||||
{ value: 'tcp', label: 'TCP' },
|
||||
{ value: 'udp', label: 'UDP' },
|
||||
{ value: 'http', label: 'HTTP' },
|
||||
{ value: 'https', label: 'HTTPS' },
|
||||
{ value: 'stcp', label: 'STCP(安全点对点)' },
|
||||
{ value: 'xtcp', label: 'XTCP(P2P)' }
|
||||
{ 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' },
|
||||
{ key: 'bind_port', label: 'protocols.frp.fields.bind_port.label', type: 'number', default: 7000, showIf: { mode: 'server' } },
|
||||
{ key: 'public_endpoint', label: 'protocols.frp.fields.public_endpoint.label', placeholder: '1.2.3.4', showIf: { mode: 'server' } },
|
||||
{ key: 'dashboard_port', label: 'protocols.frp.fields.dashboard_port.label', type: 'number', default: 7500, showIf: { mode: 'server' } },
|
||||
{ key: 'dashboard_user', label: 'protocols.frp.fields.dashboard_user.label', default: 'admin', showIf: { mode: 'server' } },
|
||||
{ key: 'dashboard_password', label: 'protocols.frp.fields.dashboard_password.label', type: 'password', secret: true, showIf: { mode: 'server' }, tip: 'protocols.frp.fields.dashboard_password.tip' },
|
||||
{ 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' },
|
||||
{ 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' },
|
||||
{ key: 'allow_ports', label: 'protocols.frp.fields.allow_ports.label', placeholder: '6000-6100,7001', showIf: { mode: 'server' }, tip: 'protocols.frp.fields.allow_ports.tip' },
|
||||
{ key: 'server_addr', label: 'protocols.frp.fields.server_addr.label', placeholder: '1.2.3.4', showIf: { mode: 'client' } },
|
||||
{ key: 'server_port', label: 'protocols.frp.fields.server_port.label', type: 'number', default: 7000, showIf: { mode: 'client' } },
|
||||
{ key: 'token', label: 'protocols.frp.fields.token.label', type: 'password', secret: true, tip: 'protocols.frp.fields.token.tip' },
|
||||
{ key: 'proxy_name', label: 'protocols.frp.fields.proxy_name.label', placeholder: 'ssh', default: 'ssh' },
|
||||
{ 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' },
|
||||
{ key: 'local_ip', label: '内网目标 IP', default: '127.0.0.1' },
|
||||
{ key: 'local_port', label: '内网目标端口', type: 'number', default: 22 },
|
||||
{ key: 'remote_port', label: '公网映射端口', type: 'number', default: 6000, showIf: { proxy_type: ['tcp', 'udp'] } },
|
||||
{ key: 'custom_domains', label: '绑定域名', placeholder: 'app.example.com', showIf: { proxy_type: ['http', 'https'] }, tip: 'HTTP/HTTPS 代理必填' },
|
||||
{ key: 'secret_key', label: 'STCP/XTCP 密钥', type: 'password', secret: true, showIf: { proxy_type: ['stcp', 'xtcp'] }, tip: '访问端与提供端需一致' }
|
||||
{ key: 'local_ip', label: 'protocols.frp.fields.local_ip.label', default: '127.0.0.1' },
|
||||
{ key: 'local_port', label: 'protocols.frp.fields.local_port.label', type: 'number', default: 22 },
|
||||
{ key: 'remote_port', label: 'protocols.frp.fields.remote_port.label', type: 'number', default: 6000, showIf: { proxy_type: ['tcp', 'udp'] } },
|
||||
{ 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' },
|
||||
{ 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' }
|
||||
]
|
||||
},
|
||||
openvpn: {
|
||||
name: 'OpenVPN',
|
||||
desc: '最成熟的开源 VPN,兼容各类老项目与系统',
|
||||
name: 'protocols.openvpn.name',
|
||||
desc: 'protocols.openvpn.desc',
|
||||
color: '#e07b39',
|
||||
icon: 'openvpn',
|
||||
scenes: '老项目兼容 / 通用接入',
|
||||
scenes: 'protocols.openvpn.scenes',
|
||||
fields: [
|
||||
{ key: 'public_endpoint', label: '公网接入地址', placeholder: 'vpn.example.com', required: true },
|
||||
{ key: 'port', label: '端口', type: 'number', default: 1194 },
|
||||
{ key: 'proto', label: '传输协议', type: 'select', options: [
|
||||
{ value: 'udp', label: 'UDP(推荐,性能更好)' },
|
||||
{ value: 'tcp-server', label: 'TCP(穿透限制网络更稳)' }
|
||||
], default: 'udp', tip: '可随时在编辑中切换;切换后需重启专线,客户端需重新下载配置' },
|
||||
{ key: 'subnet', label: 'VPN 网段', default: '10.10.0.0 255.255.255.0', tip: '如 10.8.0.0 255.255.240.0 可容纳更多客户端(/20)' },
|
||||
{ key: 'cipher', label: '加密算法', type: 'select', options: [
|
||||
{ value: 'AES-256-GCM', label: 'AES-256-GCM' },
|
||||
{ value: 'AES-128-GCM', label: 'AES-128-GCM' },
|
||||
{ value: 'AES-256-CBC', label: 'AES-256-CBC' }
|
||||
{ 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: 'udp', 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: '认证方式', type: 'select', options: [
|
||||
{ value: 'certificate', label: '仅证书' },
|
||||
{ value: 'password', label: '仅用户名密码' },
|
||||
{ value: 'certificate+password', label: '证书 + 密码' }
|
||||
], default: 'certificate', tip: '密码模式对齐生产 verify-client-cert none + username-as-common-name' },
|
||||
{ key: 'mfa_mode', label: '拨号 MFA (2FA)', type: 'select', options: [
|
||||
{ value: 'off', label: '关闭' },
|
||||
{ value: 'optional', label: '可选(用户绑定后才校验)' },
|
||||
{ value: 'required', label: '强制(所有拨号用户必须 MFA)' }
|
||||
], default: 'off', tip: 'static-challenge + TOTP;在拨号用户页管理 OTP', showIf: { auth_mode: ['password', 'certificate+password'] } },
|
||||
{ key: 'otp_slop', label: 'OTP 时钟容差(秒)', type: 'number', default: 90, showIf: { auth_mode: ['password', 'certificate+password'] } },
|
||||
{ key: 'otp_max_failures', label: 'OTP 失败锁定次数', type: 'number', default: 5, showIf: { auth_mode: ['password', 'certificate+password'] } },
|
||||
{ key: 'otp_lockout_sec', label: 'OTP 锁定时长(秒)', type: 'number', default: 300, showIf: { auth_mode: ['password', 'certificate+password'] } },
|
||||
{ key: 'otp_disallow_reuse', label: '禁止重复使用同码', type: 'switch', default: true, showIf: { auth_mode: ['password', 'certificate+password'] } },
|
||||
{ key: 'dns', label: '下发 DNS', default: '223.5.5.5' },
|
||||
{ key: 'redirect_gateway', label: '全流量代理', type: 'switch', default: true, tip: '关闭后仅推送下方内网路由(生产常只推指定路由)' },
|
||||
{ key: 'push_routes', label: '推送内网路由', placeholder: '192.168.0.0/16,10.0.0.0/8', tip: 'CIDR 逗号分隔' },
|
||||
{ key: 'enable_nat', label: '启用 NAT 出网', type: 'switch', default: false },
|
||||
{ key: 'max_clients', label: '最大客户端数', type: 'number', default: 1000, tip: '0 不限制;生产常见 1000' },
|
||||
{ key: 'keepalive_interval', label: 'Keepalive 间隔', type: 'number', default: 5, tip: '生产常用 keepalive 5 30' },
|
||||
{ key: 'keepalive_timeout', label: 'Keepalive 超时', type: 'number', default: 30 },
|
||||
{ key: 'tun_mtu', label: 'tun-mtu', type: 'number', default: 1500, tip: '生产常用 1500' },
|
||||
{ key: 'tun_mtu_extra', label: 'tun-mtu-extra', type: 'number', default: 32 },
|
||||
{ key: 'mssfix', label: 'mssfix', type: 'number', default: 0, tip: '0=不设置;TCP 生产常用 1450,选 TCP 时默认 1450' },
|
||||
{ key: 'duplicate_cn', label: '允许 duplicate-cn', type: 'switch', default: false, tip: '同用户名/证书多终端同时在线;密码模式默认会自动开启' },
|
||||
{ key: 'reneg_sec', label: 'reneg-sec', type: 'number', default: 0, tip: '0=禁用 TLS 重协商(生产/MFA 推荐);证书-only 默认可 3600' },
|
||||
{ key: 'run_as_user', label: '降权用户', placeholder: 'openvpn', tip: '对应 user openvpn;需系统已有该用户,留空不降权' },
|
||||
{ key: 'run_as_group', label: '降权组', placeholder: 'openvpn', tip: '对应 group openvpn' }
|
||||
{ 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' }
|
||||
], default: 'certificate', 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: ['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: false },
|
||||
{ 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: '接入地址', placeholder: 'host:port' },
|
||||
{ key: 'token', label: '认证凭据', type: 'password', secret: true },
|
||||
{ key: 'extra', label: '扩展参数(JSON)', placeholder: '{"key":"value"}' }
|
||||
{ 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 = {
|
||||
|
||||
Reference in new issue
Block a user