203 lines
6.9 KiB
Go
203 lines
6.9 KiB
Go
package panel
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// StringOrArray is a type that can unmarshal from either a JSON string or an array of strings.
|
|
// When it's an array, the elements are joined with newlines.
|
|
type StringOrArray string
|
|
|
|
func (s *StringOrArray) UnmarshalJSON(data []byte) error {
|
|
var str string
|
|
if err := json.Unmarshal(data, &str); err == nil {
|
|
*s = StringOrArray(str)
|
|
return nil
|
|
}
|
|
var arr []string
|
|
if err := json.Unmarshal(data, &arr); err == nil {
|
|
*s = StringOrArray(strings.Join(arr, "\n"))
|
|
return nil
|
|
}
|
|
return fmt.Errorf("StringOrArray: expected string or []string, got %s", string(data))
|
|
}
|
|
|
|
// HandshakeResponse is the response from POST /api/v2/server/handshake
|
|
type HandshakeResponse struct {
|
|
WebSocket WSConfig `json:"websocket"`
|
|
Settings Settings `json:"settings"`
|
|
}
|
|
|
|
func (h *HandshakeResponse) UnmarshalJSON(data []byte) error {
|
|
type Alias HandshakeResponse
|
|
aux := &struct {
|
|
Settings json.RawMessage `json:"settings"`
|
|
*Alias
|
|
}{
|
|
Alias: (*Alias)(h),
|
|
}
|
|
if err := json.Unmarshal(data, &aux); err != nil {
|
|
return err
|
|
}
|
|
// If settings is an empty array [], skip unmarshaling it into the struct
|
|
if len(aux.Settings) > 0 && string(aux.Settings) != "[]" {
|
|
if err := json.Unmarshal(aux.Settings, &h.Settings); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WSConfig holds WebSocket connection settings from the panel
|
|
type WSConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
WSURL string `json:"ws_url,omitempty"`
|
|
}
|
|
|
|
// Settings holds panel-defined intervals
|
|
type Settings struct {
|
|
PushInterval int `json:"push_interval"`
|
|
PullInterval int `json:"pull_interval"`
|
|
}
|
|
|
|
// NodeConfig is the response from GET /api/v1/server/UniProxy/config
|
|
type NodeConfig struct {
|
|
Protocol string `json:"protocol"`
|
|
ListenIP string `json:"listen_ip"`
|
|
ServerPort int `json:"server_port"`
|
|
Network string `json:"network"`
|
|
NetworkSettings map[string]interface{} `json:"networkSettings"`
|
|
BaseConfig BaseConfig `json:"base_config"`
|
|
Routes []RouteRule `json:"routes"`
|
|
|
|
// Kernel settings (Xboard extension)
|
|
KernelType string `json:"kernel_type,omitempty"` // "singbox" or "xray"
|
|
KernelLogLevel string `json:"kernel_log_level,omitempty"` // "info", "warn", etc.
|
|
CustomOutbounds []OutboundConfig `json:"custom_outbounds,omitempty"`
|
|
CustomRoutes []map[string]any `json:"custom_routes,omitempty"`
|
|
|
|
// Certificate settings (Xboard extension)
|
|
CertConfig *CertConfig `json:"cert_config,omitempty"`
|
|
AutoTLS bool `json:"auto_tls,omitempty"` // Deprecated: use CertConfig
|
|
Domain string `json:"domain,omitempty"` // Deprecated: use CertConfig
|
|
|
|
// Shadowsocks
|
|
Cipher string `json:"cipher,omitempty"`
|
|
Plugin string `json:"plugin,omitempty"`
|
|
PluginOpt string `json:"plugin_opts,omitempty"`
|
|
ServerKey string `json:"server_key,omitempty"`
|
|
|
|
// VMess / VLESS
|
|
TLS int `json:"tls,omitempty"`
|
|
Flow string `json:"flow,omitempty"`
|
|
Decryption string `json:"decryption,omitempty"`
|
|
TLSSettings map[string]interface{} `json:"tls_settings,omitempty"`
|
|
|
|
// Trojan
|
|
Host string `json:"host,omitempty"`
|
|
ServerName string `json:"server_name,omitempty"`
|
|
|
|
// Hysteria
|
|
Version int `json:"version,omitempty"`
|
|
UpMbps int `json:"up_mbps,omitempty"`
|
|
DownMbps int `json:"down_mbps,omitempty"`
|
|
Obfs string `json:"obfs,omitempty"`
|
|
ObfsPassword string `json:"obfs-password,omitempty"`
|
|
|
|
// TUIC
|
|
CongestionControl string `json:"congestion_control,omitempty"`
|
|
|
|
// AnyTLS
|
|
PaddingScheme StringOrArray `json:"padding_scheme,omitempty"`
|
|
|
|
// Mieru
|
|
Transport string `json:"transport,omitempty"`
|
|
TrafficPattern string `json:"traffic_pattern,omitempty"`
|
|
|
|
// Multiplex
|
|
Multiplex *MultiplexConfig `json:"multiplex,omitempty"`
|
|
|
|
// Proxy Protocol (supports both top-level and networkSettings for compatibility)
|
|
AcceptProxyProtocol bool `json:"accept_proxy_protocol,omitempty"`
|
|
}
|
|
|
|
// GetProxyProtocol returns true if AcceptProxyProtocol is set either at node level
|
|
// or in networkSettings (for panel compatibility).
|
|
func (nc *NodeConfig) GetProxyProtocol() bool {
|
|
if nc.AcceptProxyProtocol {
|
|
return true
|
|
}
|
|
if nc.NetworkSettings != nil {
|
|
if v, ok := nc.NetworkSettings["acceptProxyProtocol"]; ok {
|
|
if b, ok := v.(bool); ok {
|
|
return b
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type MultiplexConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
Protocol string `json:"protocol"`
|
|
MaxConnections int `json:"max_connections"`
|
|
MinStreams int `json:"min_streams"`
|
|
MaxStreams int `json:"max_streams"`
|
|
Padding bool `json:"padding"`
|
|
Brutal *BrutalConfig `json:"brutal,omitempty"`
|
|
}
|
|
|
|
type BrutalConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
UpMbps int `json:"up_mbps"`
|
|
DownMbps int `json:"down_mbps"`
|
|
}
|
|
|
|
// CertConfig holds certificate automation settings from the panel
|
|
type CertConfig struct {
|
|
CertMode string `json:"cert_mode"` // none, dns, http, self, file
|
|
Domain string `json:"domain"` // Certificate domain
|
|
Email string `json:"email"` // ACME email
|
|
DNSProvider string `json:"dns_provider"` // dns mode: cloudflare, alidns, etc.
|
|
DNSEnv map[string]string `json:"dns_env"` // Provider-specific API keys/tokens
|
|
HTTPPort int `json:"http_port"` // ACME HTTP-01 local port (default 80)
|
|
CertFile string `json:"cert_file"` // file mode: path to cert file
|
|
KeyFile string `json:"key_file"` // file mode: path to key file
|
|
CertContent string `json:"cert_content"` // content mode: certificate raw string
|
|
KeyContent string `json:"key_content"` // content mode: private key raw string
|
|
}
|
|
|
|
// OutboundConfig defines a custom outbound for kernel
|
|
type OutboundConfig struct {
|
|
Tag string `json:"tag"` // Unique tag for routing
|
|
Protocol string `json:"protocol"` // vmess, vless, shadowsocks, wireguard, etc.
|
|
Settings map[string]any `json:"settings,omitempty"` // Protocol-specific settings
|
|
ProxyTag string `json:"proxy_tag,omitempty"` // Chain proxy: next outbound tag
|
|
}
|
|
|
|
type BaseConfig struct {
|
|
PushInterval int `json:"push_interval"`
|
|
PullInterval int `json:"pull_interval"`
|
|
}
|
|
|
|
type RouteRule struct {
|
|
ID int `json:"id"`
|
|
Match []string `json:"match"`
|
|
Action string `json:"action"`
|
|
ActionValue string `json:"action_value,omitempty"`
|
|
}
|
|
|
|
// User represents a user returned by the panel
|
|
type User struct {
|
|
ID int `json:"id"`
|
|
UUID string `json:"uuid"`
|
|
SpeedLimit int `json:"speed_limit"` // Mbps, 0 = unlimited
|
|
DeviceLimit int `json:"device_limit"` // max devices, 0 = unlimited
|
|
}
|
|
|
|
type UsersResponse struct {
|
|
Users []User `json:"users"`
|
|
}
|