228 lines
19 KiB
JavaScript
228 lines
19 KiB
JavaScript
// 各协议的创建向导表单定义(前端动态渲染)
|
||
// 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
|
||
}
|