diff --git a/service/xboard/service.go b/service/xboard/service.go index 14b734b4..f86f0600 100644 --- a/service/xboard/service.go +++ b/service/xboard/service.go @@ -68,16 +68,59 @@ type XNodeConfig struct { } type XRealitySettings struct { - Dest string `json:"dest"` - ServerNames []string `json:"serverNames"` - PrivateKey string `json:"privateKey"` - ShortId string `json:"shortId"` + Dest string `json:"dest"` + ServerNames []string `json:"serverNames"` + ServerNames_ []string `json:"server_names"` + PrivateKey string `json:"privateKey"` + PrivateKey_ string `json:"private_key"` + ShortId string `json:"shortId"` + ShortId_ string `json:"short_id"` + ShortIds []string `json:"shortIds"` + ShortIds_ []string `json:"short_ids"` +} + +func (r *XRealitySettings) GetPrivateKey() string { + if r.PrivateKey != "" { + return r.PrivateKey + } + return r.PrivateKey_ +} + +func (r *XRealitySettings) GetShortIds() []string { + if len(r.ShortIds) > 0 { + return r.ShortIds + } + if len(r.ShortIds_) > 0 { + return r.ShortIds_ + } + if r.ShortId != "" { + return []string{r.ShortId} + } + if r.ShortId_ != "" { + return []string{r.ShortId_} + } + return nil +} + +func (r *XRealitySettings) GetServerNames() []string { + if len(r.ServerNames) > 0 { + return r.ServerNames + } + return r.ServerNames_ } type XStreamSettings struct { Network string `json:"network"` Security string `json:"security"` RealitySettings XRealitySettings `json:"realitySettings"` + RealitySettings_ XRealitySettings `json:"reality_settings"` +} + +func (s *XStreamSettings) GetReality() *XRealitySettings { + if s.RealitySettings.GetPrivateKey() != "" { + return &s.RealitySettings + } + return &s.RealitySettings_ } func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.XBoardServiceOptions) (adapter.Service, error) { @@ -155,20 +198,26 @@ func (s *Service) setupNode() error { // Handle Reality var streamSettings XStreamSettings json.Unmarshal(config.Config.StreamSettings, &streamSettings) - if streamSettings.Security == "reality" { + reality := streamSettings.GetReality() + if streamSettings.Security == "reality" && reality != nil { + serverNames := reality.GetServerNames() + serverName := "" + if len(serverNames) > 0 { + serverName = serverNames[0] + } vlessOptions.TLS = &option.InboundTLSOptions{ Enabled: true, - ServerName: streamSettings.RealitySettings.ServerNames[0], + ServerName: serverName, Reality: &option.InboundRealityOptions{ Enabled: true, Handshake: option.InboundRealityHandshakeOptions{ ServerOptions: option.ServerOptions{ - Server: streamSettings.RealitySettings.Dest, + Server: reality.Dest, ServerPort: 443, }, }, - PrivateKey: streamSettings.RealitySettings.PrivateKey, - ShortID: badoption.Listable[string]{streamSettings.RealitySettings.ShortId}, + PrivateKey: reality.GetPrivateKey(), + ShortID: badoption.Listable[string](reality.GetShortIds()), }, } } @@ -252,11 +301,14 @@ func (s *Service) fetchConfig() (*XNodeConfig, error) { return nil, E.New("failed to fetch config, status: ", resp.Status, ", body: ", string(respBody)) } + body, _ := io.ReadAll(resp.Body) + var result struct { Data XNodeConfig `json:"data"` } - err = json.NewDecoder(resp.Body).Decode(&result) + err = json.Unmarshal(body, &result) if err != nil { + s.logger.Debug("Xboard raw config response: ", string(body)) return nil, err } return &result.Data, nil @@ -289,7 +341,7 @@ type userData struct { func (s *Service) syncUsers() { s.logger.Info("Xboard sync users...") - xUsers, err := s.fetchUsers() + users, err := s.fetchUsers() if err != nil { s.logger.Error("Xboard sync error: ", err) return @@ -299,11 +351,8 @@ func (s *Service) syncUsers() { defer s.access.Unlock() newUsers := make(map[string]userData) - for _, u := range xUsers { - key := u.UUID - if key == "" { - key = u.Passwd - } + for _, u := range users { + key := u.ResolveKey() if key == "" { continue } @@ -468,11 +517,26 @@ func (s *Service) Close() error { // Xboard User Model type XUser struct { - ID int `json:"id"` - Email string `json:"email"` - UUID string `json:"uuid"` - Passwd string `json:"passwd"` - Flow string `json:"flow"` + ID int `json:"id"` + Email string `json:"email"` + UUID string `json:"uuid"` // V2ray/Vless + Passwd string `json:"passwd"` // SS + Password string `json:"password"` // Trojan/SS alternate + Token string `json:"token"` // Alternate + Flow string `json:"flow"` +} + +func (u *XUser) ResolveKey() string { + if u.UUID != "" { + return u.UUID + } + if u.Passwd != "" { + return u.Passwd + } + if u.Password != "" { + return u.Password + } + return u.Token } func (s *Service) fetchUsers() ([]XUser, error) { @@ -499,11 +563,14 @@ func (s *Service) fetchUsers() ([]XUser, error) { return nil, E.New("failed to fetch users, status: ", resp.Status, ", body: ", string(respBody)) } + body, _ := io.ReadAll(resp.Body) + var result struct { Data []XUser `json:"data"` } - err = json.NewDecoder(resp.Body).Decode(&result) + err = json.Unmarshal(body, &result) if err != nil { + s.logger.Debug("Xboard raw user response: ", string(body)) return nil, err } return result.Data, nil