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:
opsx-tools committed 2026-07-23 12:57:46 +08:00
1 parent 021d012478
commit 91974fc30f
26 files changed
+1977 -377

No files matched your search

+421 -5
View File
@@ -23,7 +23,7 @@
"name": "Name",
"description": "Description",
"username": "Username",
"password": "Password",
"password": "***",
"email": "Email",
"source": "Source",
"local": "Local",
@@ -51,7 +51,8 @@
"noData": "No data",
"never": "Never",
"copiedToClipboard": "Copied to clipboard",
"logout": "Logout"
"logout": "Logout",
"batchOperation": "Batch Operation"
},
"login": {
"title": "VPN Management Platform",
@@ -102,7 +103,8 @@
"recommendedCmd": "Recommended Command",
"otherDistros": "Other Distros",
"copyRecommended": "Copy Recommended",
"getInstallCmdFailed": "Failed to get install command"
"getInstallCmdFailed": "Failed to get install command",
"aptDefault": "apt default"
},
"tunnels": {
"searchPlaceholder": "Search by name",
@@ -184,7 +186,28 @@
"qrFailed": "Failed to generate QR code",
"noClientConfigWarn": "No client config available",
"deleteTunnelConfirm": "Delete tunnel \"{name}\"? Configuration and keys will be permanently removed.",
"peerAlreadyAdded": "Peer already added"
"peerAlreadyAdded": "Peer already added",
"stopFailed": "Stop failed",
"selected": "{count} selected",
"batchStart": "Batch Start",
"batchStop": "Batch Stop",
"batchDelete": "Batch Delete",
"batchStartConfirm": "Confirm batch start {count} tunnels?",
"batchStopConfirm": "Confirm batch stop {count} tunnels?",
"batchDeleteConfirm": "Confirm batch delete {count} tunnels? This cannot be undone!",
"batchStarted": "Batch operation submitted, executing in background",
"taskProgress": "Task Progress",
"taskPending": "Pending",
"taskRunning": "Running",
"taskDone": "Done",
"taskFailed": "Failed",
"taskSuccess": "Success {count}/{total}",
"taskFailedCount": "Failed {count}",
"taskInProgress": "In progress ({done}/{total})",
"taskComplete": "All done",
"taskPartialFail": "Partial failure",
"viewTasks": "View Tasks",
"noTasks": "No task history"
},
"tunnelEditor": {
"title": "Edit Tunnel",
@@ -295,7 +318,9 @@
"ldapLoadFailed": "LDAP load failed",
"ldapConfigSaved": "LDAP configuration saved",
"ldapConnected": "LDAP connection successful",
"ldapConnectFailed": "Connection failed"
"ldapConnectFailed": "Connection failed",
"emptyUsername": "(empty)",
"errorDetails": "Error details:"
},
"vpnUsers": {
"title": "VPN Dial-in Users",
@@ -333,6 +358,7 @@
"lockedUntil": "Yes (until {time})",
"lastOtpSuccess": "Last OTP Success",
"compatible": "Compatible",
"totpCompatible": "TOTP standard (compatible with Google/Microsoft Authenticator)",
"bindAuthenticator": "Bind Authenticator",
"disableMfa": "Disable MFA",
"regenBackupCodes": "Regenerate Backup Codes",
@@ -580,5 +606,395 @@
},
"protocolIcon": {
"custom": "Custom Protocol"
},
"protocols": {
"wireguard": {
"name": "WireGuard",
"desc": "High-performance modern VPN with kernel-level implementation, roaming-friendly",
"scenes": "Internal Access / Mobile Office",
"fields": {
"address": {
"label": "Server VPN Subnet Address",
"tip": "Server's address within the VPN subnet (CIDR)"
},
"listen_port": {
"label": "Listen Port"
},
"client_address": {
"label": "First Client Address",
"tip": "Add more peers in the detail page after creation"
},
"public_endpoint": {
"label": "Public Endpoint",
"tip": "For client connections — public IP:port"
},
"dns": {
"label": "DNS"
},
"allowed_ips": {
"label": "Client AllowedIPs",
"tip": "Use 0.0.0.0/0 for full tunnel; specify internal CIDRs for split tunnel"
},
"keepalive": {
"label": "Keepalive (sec)",
"tip": "Recommended 15–25 for clients behind NAT"
},
"mtu": {
"label": "MTU",
"tip": "0 for default; common range 1280–1420 over public networks"
},
"enable_nat": {
"label": "Enable NAT Outbound",
"tip": "Enable when clients need internet or other subnet access"
},
"egress_interface": {
"label": "NAT Egress Interface",
"tip": "Leave empty to auto-detect the default route interface"
}
}
},
"ipsec": {
"name": "IPSec Site-to-Site",
"desc": "Site-to-site connectivity with third-party devices (Cisco/Huawei/FortiGate, etc.)",
"scenes": "Third-Party Integration / Site-to-Site",
"fields": {
"vendor_template": {
"label": "Vendor Template",
"tip": "Auto-fills Phase 1/Phase 2 proposals, still manually editable",
"options": {
"generic": "Generic Standard (Recommended)",
"cisco": "Cisco ISR/ASR",
"fortigate": "FortiGate",
"huawei": "Huawei USG/AR",
"h3c": "H3C"
}
},
"public_endpoint": {
"label": "Local Public IP"
},
"remote_gateway": {
"label": "Remote Gateway"
},
"local_subnets": {
"label": "Local Subnets",
"tip": "Separate multiple subnets with commas"
},
"remote_subnets": {
"label": "Remote Subnets"
},
"psk": {
"label": "Pre-Shared Key (PSK)"
},
"ike_version": {
"label": "IKE Version",
"options": {
"ikev2": "IKEv2",
"ikev1": "IKEv1"
}
},
"ike_proposal": {
"label": "Phase 1 Proposal",
"tip": "Encryption-Auth-DH group, must match remote side"
},
"esp_proposal": {
"label": "Phase 2 Proposal"
},
"pfs_group": {
"label": "PFS DH Group"
},
"ike_lifetime": {
"label": "IKE Lifetime (sec)"
},
"local_id": {
"label": "Local ID"
},
"remote_id": {
"label": "Remote ID"
}
}
},
"ikev2": {
"name": "IKEv2 Remote Access",
"desc": "Native VPN dial-in from phones and laptops, more modern than L2TP",
"scenes": "Remote Office / Native VPN",
"fields": {
"public_endpoint": {
"label": "Server Public Address"
},
"local_id": {
"label": "Server ID / Remote ID",
"tip": "Must match the client's Remote ID"
},
"psk": {
"label": "Machine Auth PSK",
"tip": "Leave empty to auto-generate; shared key for iOS/Android"
},
"username": {
"label": "Default Dial-in User"
},
"password": {
"label": "Default Dial-in Password",
"tip": "Leave empty to auto-generate; add more users in VPN Dial-in Users"
},
"address_pool": {
"label": "Client Address Pool"
},
"dns": {
"label": "Push DNS"
},
"local_ts": {
"label": "Allowed Subnets",
"tip": "0.0.0.0/0 for full tunnel; change to internal CIDR for split tunnel"
},
"ike_proposal": {
"label": "IKE Proposal"
},
"esp_proposal": {
"label": "ESP Proposal"
}
}
},
"l2tp": {
"name": "L2TP/IPSec",
"desc": "Best compatibility — natively supported by phones, legacy devices, and routers",
"scenes": "Mobile Devices / Legacy Compatibility",
"fields": {
"public_endpoint": {
"label": "Server Public IP"
},
"psk": {
"label": "IPSec Pre-Shared Key"
},
"username": {
"label": "Default Dial-in Username",
"tip": "Add more users for this tunnel in VPN Dial-in Users"
},
"password": {
"label": "Default Dial-in Password",
"tip": "Leave empty if using only the dial-in user table (at least one method required at creation)"
},
"ip_range": {
"label": "Client Address Pool"
},
"local_ip": {
"label": "Server Tunnel Address"
},
"dns": {
"label": "Push DNS"
}
}
},
"frp": {
"name": "FRP NAT Traversal",
"desc": "TCP/UDP/HTTP port forwarding and reverse proxy for NAT traversal",
"scenes": "NAT Traversal / Port Forwarding",
"fields": {
"mode": {
"label": "Mode",
"tip": "server = frps (public side), client = frpc (LAN side)",
"options": {
"server": "server (frps — public side)",
"client": "client (frpc — LAN side)"
}
},
"bind_port": {
"label": "Bind Port (server)"
},
"public_endpoint": {
"label": "Public Address (server)"
},
"dashboard_port": {
"label": "Dashboard Port (server)"
},
"dashboard_user": {
"label": "Dashboard User (server)"
},
"dashboard_password": {
"label": "Dashboard Password (server)",
"tip": "Auto-generates a strong password if left empty; keeps current password when editing"
},
"vhost_http_port": {
"label": "HTTP VHost Port",
"tip": "0 = disabled; must be >0 for HTTP proxying"
},
"vhost_https_port": {
"label": "HTTPS VHost Port",
"tip": "0 = disabled"
},
"allow_ports": {
"label": "Allowed Port Range",
"tip": "Restricts which remotePorts frpc can request"
},
"server_addr": {
"label": "frps Address (client)"
},
"server_port": {
"label": "frps Port (client)"
},
"token": {
"label": "Auth Token",
"tip": "Leave empty to auto-generate"
},
"proxy_name": {
"label": "Proxy Name"
},
"proxy_type": {
"label": "Proxy Type",
"options": {
"tcp": "TCP",
"udp": "UDP",
"http": "HTTP",
"https": "HTTPS",
"stcp": "STCP (Secure P2P)",
"xtcp": "XTCP (P2P)"
}
},
"local_ip": {
"label": "Local Target IP"
},
"local_port": {
"label": "Local Target Port"
},
"remote_port": {
"label": "Public Mapped Port"
},
"custom_domains": {
"label": "Custom Domains",
"tip": "Required for HTTP/HTTPS proxy"
},
"secret_key": {
"label": "STCP/XTCP Secret Key",
"tip": "Must match between visitor and server"
}
}
},
"openvpn": {
"name": "OpenVPN",
"desc": "Most mature open-source VPN, compatible with legacy systems and projects",
"scenes": "Legacy Compatibility / General Access",
"fields": {
"public_endpoint": {
"label": "Public Endpoint"
},
"port": {
"label": "Port"
},
"proto": {
"label": "Transport Protocol",
"tip": "Can be switched in edit mode; requires tunnel restart and client re-download",
"options": {
"udp": "UDP (Recommended, better performance)",
"tcp-server": "TCP (More stable through restrictive networks)"
}
},
"subnet": {
"label": "VPN Subnet",
"tip": "e.g., 10.8.0.0 255.255.240.0 for more clients (/20)"
},
"cipher": {
"label": "Cipher",
"options": {
"AES-256-GCM": "AES-256-GCM",
"AES-128-GCM": "AES-128-GCM",
"AES-256-CBC": "AES-256-CBC"
}
},
"auth_mode": {
"label": "Authentication Mode",
"tip": "Password mode aligns with verify-client-cert none + username-as-common-name",
"options": {
"certificate": "Certificate Only",
"password": "***",
"certificate+password": "Certificate + Password"
}
},
"mfa_mode": {
"label": "Dial-in MFA (2FA)",
"tip": "static-challenge + TOTP; manage OTP in VPN Dial-in Users",
"options": {
"off": "Disabled",
"optional": "Optional (verified after user binds)",
"required": "Required (all dial-in users must use MFA)"
}
},
"otp_slop": {
"label": "OTP Clock Tolerance (sec)"
},
"otp_max_failures": {
"label": "OTP Lockout Threshold"
},
"otp_lockout_sec": {
"label": "OTP Lockout Duration (sec)"
},
"otp_disallow_reuse": {
"label": "Disallow OTP Reuse"
},
"dns": {
"label": "Push DNS"
},
"redirect_gateway": {
"label": "Full Tunnel",
"tip": "When off, only pushes internal routes below (common in production)"
},
"push_routes": {
"label": "Push Internal Routes",
"tip": "CIDR, comma-separated"
},
"enable_nat": {
"label": "Enable NAT Outbound"
},
"max_clients": {
"label": "Max Clients",
"tip": "0 = unlimited; 1000 is common in production"
},
"keepalive_interval": {
"label": "Keepalive Interval",
"tip": "Production typical: keepalive 5 30"
},
"keepalive_timeout": {
"label": "Keepalive Timeout"
},
"tun_mtu": {
"label": "tun-mtu",
"tip": "Production typical: 1500"
},
"tun_mtu_extra": {
"label": "tun-mtu-extra"
},
"mssfix": {
"label": "mssfix",
"tip": "0 = unset; TCP production typical 1450; defaults to 1450 when TCP is selected"
},
"duplicate_cn": {
"label": "Allow duplicate-cn",
"tip": "Same username/cert on multiple devices simultaneously; auto-enabled in password mode"
},
"reneg_sec": {
"label": "reneg-sec",
"tip": "0 = disable TLS re-negotiation (recommended for production/MFA); cert-only default can be 3600"
},
"run_as_user": {
"label": "Drop Privileges User",
"tip": "Maps to 'user openvpn'; user must exist on the system; leave empty to run as root"
},
"run_as_group": {
"label": "Drop Privileges Group",
"tip": "Maps to 'group openvpn'"
}
}
},
"custom": {
"fields": {
"endpoint": {
"label": "Endpoint"
},
"token": {
"label": "Auth Credential"
},
"extra": {
"label": "Extra Parameters (JSON)"
}
}
}
}
}