2020-11-25 19:01:53 +08:00
package conf
import (
"encoding/json"
2024-06-29 14:32:57 -04:00
"github.com/xtls/xray-core/common/errors"
2020-12-04 09:36:16 +08:00
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/http"
2023-08-10 04:43:34 +00:00
"google.golang.org/protobuf/proto"
2020-11-25 19:01:53 +08:00
)
type HTTPAccount struct {
Username string `json:"user"`
Password string `json:"pass"`
}
func ( v * HTTPAccount ) Build () * http . Account {
return & http . Account {
Username : v . Username ,
Password : v . Password ,
}
}
type HTTPServerConfig struct {
2026-05-07 19:10:48 +08:00
Users [] * HTTPAccount `json:"users"`
2020-11-25 19:01:53 +08:00
Accounts [] * HTTPAccount `json:"accounts"`
Transparent bool `json:"allowTransparent"`
UserLevel uint32 `json:"userLevel"`
}
func ( c * HTTPServerConfig ) Build () ( proto . Message , error ) {
config := & http . ServerConfig {
AllowTransparent : c . Transparent ,
UserLevel : c . UserLevel ,
}
2026-05-07 19:10:48 +08:00
if c . Accounts != nil {
c . Users = c . Accounts
}
// TODO: PB
if len ( c . Users ) > 0 {
2020-11-25 19:01:53 +08:00
config . Accounts = make ( map [ string ] string )
2026-05-07 19:10:48 +08:00
for _ , account := range c . Users {
2020-11-25 19:01:53 +08:00
config . Accounts [ account . Username ] = account . Password
}
}
return config , nil
}
type HTTPRemoteConfig struct {
Address * Address `json:"address"`
Port uint16 `json:"port"`
Users [] json . RawMessage `json:"users"`
}
2021-10-19 12:57:14 -04:00
2020-11-25 19:01:53 +08:00
type HTTPClientConfig struct {
2026-05-07 19:10:48 +08:00
Address * Address `json:"address"`
Port uint16 `json:"port"`
2025-09-11 21:48:20 +08:00
Level uint32 `json:"level"`
Email string `json:"email"`
Username string `json:"user"`
Password string `json:"pass"`
Servers [] * HTTPRemoteConfig `json:"servers"`
Headers map [ string ] string `json:"headers"`
2020-11-25 19:01:53 +08:00
}
func ( v * HTTPClientConfig ) Build () ( proto . Message , error ) {
config := new ( http . ClientConfig )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
v . Servers = [] * HTTPRemoteConfig {
{
Address : v . Address ,
Port : v . Port ,
},
}
2025-09-15 21:31:27 +08:00
if len ( v . Username ) > 0 {
v . Servers [ 0 ]. Users = [] json . RawMessage {{}}
}
}
if len ( v . Servers ) != 1 {
return nil , errors . New ( `HTTP settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple HTTP outbounds and routing balancer instead` )
2025-09-11 21:48:20 +08:00
}
2025-09-15 21:31:27 +08:00
for _ , serverConfig := range v . Servers {
if len ( serverConfig . Users ) > 1 {
return nil , errors . New ( `HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP outbounds and routing balancer instead` )
}
2020-11-25 19:01:53 +08:00
server := & protocol . ServerEndpoint {
Address : serverConfig . Address . Build (),
Port : uint32 ( serverConfig . Port ),
}
for _ , rawUser := range serverConfig . Users {
user := new ( protocol . User )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
user . Level = v . Level
user . Email = v . Email
} else {
if err := json . Unmarshal ( rawUser , user ); err != nil {
return nil , errors . New ( "failed to parse HTTP user" ). Base ( err ). AtError ()
}
2020-11-25 19:01:53 +08:00
}
account := new ( HTTPAccount )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
account . Username = v . Username
account . Password = v . Password
} else {
if err := json . Unmarshal ( rawUser , account ); err != nil {
return nil , errors . New ( "failed to parse HTTP account" ). Base ( err ). AtError ()
}
2020-11-25 19:01:53 +08:00
}
user . Account = serial . ToTypedMessage ( account . Build ())
2025-09-15 21:31:27 +08:00
server . User = user
break
2020-11-25 19:01:53 +08:00
}
2025-09-15 21:31:27 +08:00
config . Server = server
break
2020-11-25 19:01:53 +08:00
}
2022-12-15 19:15:43 +08:00
config . Header = make ([] * http . Header , 0 , 32 )
for key , value := range v . Headers {
config . Header = append ( config . Header , & http . Header {
Key : key ,
Value : value ,
})
}
2020-11-25 19:01:53 +08:00
return config , nil
}