diff --git a/infra/conf/http.go b/infra/conf/http.go index 7f59bd79..d4092f88 100644 --- a/infra/conf/http.go +++ b/infra/conf/http.go @@ -51,12 +51,27 @@ type HTTPRemoteConfig struct { } type HTTPClientConfig struct { - Servers []*HTTPRemoteConfig `json:"servers"` - Headers map[string]string `json:"headers"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + 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"` } func (v *HTTPClientConfig) Build() (proto.Message, error) { config := new(http.ClientConfig) + if v.Address != nil { + v.Servers = []*HTTPRemoteConfig{ + { + Address: v.Address, + Port: v.Port, + Users: []json.RawMessage{{}}, + }, + } + } config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) for idx, serverConfig := range v.Servers { server := &protocol.ServerEndpoint{ @@ -65,12 +80,22 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) { } for _, rawUser := range serverConfig.Users { user := new(protocol.User) - if err := json.Unmarshal(rawUser, user); err != nil { - return nil, errors.New("failed to parse HTTP user").Base(err).AtError() + 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() + } } account := new(HTTPAccount) - if err := json.Unmarshal(rawUser, account); err != nil { - return nil, errors.New("failed to parse HTTP account").Base(err).AtError() + 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() + } } user.Account = serial.ToTypedMessage(account.Build()) server.User = append(server.User, user) diff --git a/infra/conf/shadowsocks.go b/infra/conf/shadowsocks.go index f12040a6..a05c1dc5 100644 --- a/infra/conf/shadowsocks.go +++ b/infra/conf/shadowsocks.go @@ -162,20 +162,44 @@ func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) { type ShadowsocksServerTarget struct { Address *Address `json:"address"` Port uint16 `json:"port"` + Level byte `json:"level"` + Email string `json:"email"` Cipher string `json:"method"` Password string `json:"password"` - Email string `json:"email"` - Level byte `json:"level"` IVCheck bool `json:"ivCheck"` UoT bool `json:"uot"` UoTVersion int `json:"uotVersion"` } type ShadowsocksClientConfig struct { + Address *Address `json:"address"` + Port uint16 `json:"port"` + Level byte `json:"level"` + Email string `json:"email"` + Cipher string `json:"method"` + Password string `json:"password"` + IVCheck bool `json:"ivCheck"` + UoT bool `json:"uot"` + UoTVersion int `json:"uotVersion"` Servers []*ShadowsocksServerTarget `json:"servers"` } func (v *ShadowsocksClientConfig) Build() (proto.Message, error) { + if v.Address != nil { + v.Servers = []*ShadowsocksServerTarget{ + { + Address: v.Address, + Port: v.Port, + Level: v.Level, + Email: v.Email, + Cipher: v.Cipher, + Password: v.Password, + IVCheck: v.IVCheck, + UoT: v.UoT, + UoTVersion: v.UoTVersion, + }, + } + } if len(v.Servers) == 0 { return nil, errors.New("0 Shadowsocks server configured.") } diff --git a/infra/conf/socks.go b/infra/conf/socks.go index 4e14ffdc..6955001f 100644 --- a/infra/conf/socks.go +++ b/infra/conf/socks.go @@ -70,11 +70,26 @@ type SocksRemoteConfig struct { } type SocksClientConfig struct { - Servers []*SocksRemoteConfig `json:"servers"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + Level uint32 `json:"level"` + Email string `json:"email"` + Username string `json:"user"` + Password string `json:"pass"` + Servers []*SocksRemoteConfig `json:"servers"` } func (v *SocksClientConfig) Build() (proto.Message, error) { config := new(socks.ClientConfig) + if v.Address != nil { + v.Servers = []*SocksRemoteConfig{ + { + Address: v.Address, + Port: v.Port, + Users: []json.RawMessage{{}}, + }, + } + } config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) for idx, serverConfig := range v.Servers { server := &protocol.ServerEndpoint{ @@ -83,12 +98,22 @@ func (v *SocksClientConfig) Build() (proto.Message, error) { } for _, rawUser := range serverConfig.Users { user := new(protocol.User) - if err := json.Unmarshal(rawUser, user); err != nil { - return nil, errors.New("failed to parse Socks user").Base(err).AtError() + 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 Socks user").Base(err).AtError() + } } account := new(SocksAccount) - if err := json.Unmarshal(rawUser, account); err != nil { - return nil, errors.New("failed to parse socks account").Base(err).AtError() + 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 socks account").Base(err).AtError() + } } user.Account = serial.ToTypedMessage(account.Build()) server.User = append(server.User, user) diff --git a/infra/conf/socks_test.go b/infra/conf/socks_test.go index bd7b570a..da609de8 100644 --- a/infra/conf/socks_test.go +++ b/infra/conf/socks_test.go @@ -86,5 +86,36 @@ func TestSocksOutboundConfig(t *testing.T) { }, }, }, + { + Input: `{ + "address": "127.0.0.1", + "port": 1234, + "user": "test user", + "pass": "test pass", + "email": "test@email.com" + }`, + Parser: loadJSON(creator), + Output: &socks.ClientConfig{ + Server: []*protocol.ServerEndpoint{ + { + Address: &net.IPOrDomain{ + Address: &net.IPOrDomain_Ip{ + Ip: []byte{127, 0, 0, 1}, + }, + }, + Port: 1234, + User: []*protocol.User{ + { + Email: "test@email.com", + Account: serial.ToTypedMessage(&socks.Account{ + Username: "test user", + Password: "test pass", + }), + }, + }, + }, + }, + }, + }, }) } diff --git a/infra/conf/trojan.go b/infra/conf/trojan.go index 4a230514..d7d4ea17 100644 --- a/infra/conf/trojan.go +++ b/infra/conf/trojan.go @@ -20,19 +20,37 @@ import ( type TrojanServerTarget struct { Address *Address `json:"address"` Port uint16 `json:"port"` - Password string `json:"password"` - Email string `json:"email"` Level byte `json:"level"` + Email string `json:"email"` + Password string `json:"password"` Flow string `json:"flow"` } // TrojanClientConfig is configuration of trojan servers type TrojanClientConfig struct { + Address *Address `json:"address"` + Port uint16 `json:"port"` + Level byte `json:"level"` + Email string `json:"email"` + Password string `json:"password"` + Flow string `json:"flow"` Servers []*TrojanServerTarget `json:"servers"` } // Build implements Buildable func (c *TrojanClientConfig) Build() (proto.Message, error) { + if c.Address != nil { + c.Servers = []*TrojanServerTarget{ + { + Address: c.Address, + Port: c.Port, + Level: c.Level, + Email: c.Email, + Password: c.Password, + Flow: c.Flow, + }, + } + } if len(c.Servers) == 0 { return nil, errors.New("0 Trojan server configured.") } diff --git a/infra/conf/vless_test.go b/infra/conf/vless_test.go index 8f1baaa5..480d3b86 100644 --- a/infra/conf/vless_test.go +++ b/infra/conf/vless_test.go @@ -57,6 +57,39 @@ func TestVLessOutbound(t *testing.T) { }, }, }, + { + Input: `{ + "address": "example.com", + "port": 443, + "id": "27848739-7e62-4138-9fd3-098a63964b6b", + "flow": "xtls-rprx-vision-udp443", + "encryption": "none", + "level": 0 + }`, + Parser: loadJSON(creator), + Output: &outbound.Config{ + Vnext: []*protocol.ServerEndpoint{ + { + Address: &net.IPOrDomain{ + Address: &net.IPOrDomain_Domain{ + Domain: "example.com", + }, + }, + Port: 443, + User: []*protocol.User{ + { + Account: serial.ToTypedMessage(&vless.Account{ + Id: "27848739-7e62-4138-9fd3-098a63964b6b", + Flow: "xtls-rprx-vision-udp443", + Encryption: "none", + }), + Level: 0, + }, + }, + }, + }, + }, + }, }) } diff --git a/infra/conf/vmess.go b/infra/conf/vmess.go index 90ab92d4..c0171c4b 100644 --- a/infra/conf/vmess.go +++ b/infra/conf/vmess.go @@ -117,13 +117,28 @@ type VMessOutboundTarget struct { } type VMessOutboundConfig struct { - Receivers []*VMessOutboundTarget `json:"vnext"` + Address *Address `json:"address"` + Port uint16 `json:"port"` + Level uint32 `json:"level"` + Email string `json:"email"` + ID string `json:"id"` + Security string `json:"security"` + Experiments string `json:"experiments"` + Receivers []*VMessOutboundTarget `json:"vnext"` } // Build implements Buildable func (c *VMessOutboundConfig) Build() (proto.Message, error) { config := new(outbound.Config) - + if c.Address != nil { + c.Receivers = []*VMessOutboundTarget{ + { + Address: c.Address, + Port: c.Port, + Users: []json.RawMessage{{}}, + }, + } + } if len(c.Receivers) == 0 { return nil, errors.New("0 VMess receiver configured") } @@ -141,12 +156,23 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) { } for _, rawUser := range rec.Users { user := new(protocol.User) - if err := json.Unmarshal(rawUser, user); err != nil { - return nil, errors.New("invalid VMess user").Base(err) + if c.Address != nil { + user.Level = c.Level + user.Email = c.Email + } else { + if err := json.Unmarshal(rawUser, user); err != nil { + return nil, errors.New("invalid VMess user").Base(err) + } } account := new(VMessAccount) - if err := json.Unmarshal(rawUser, account); err != nil { - return nil, errors.New("invalid VMess user").Base(err) + if c.Address != nil { + account.ID = c.ID + account.Security = c.Security + account.Experiments = c.Experiments + } else { + if err := json.Unmarshal(rawUser, account); err != nil { + return nil, errors.New("invalid VMess user").Base(err) + } } u, err := uuid.ParseString(account.ID) diff --git a/infra/conf/vmess_test.go b/infra/conf/vmess_test.go index 8adda170..e3bf1349 100644 --- a/infra/conf/vmess_test.go +++ b/infra/conf/vmess_test.go @@ -58,6 +58,40 @@ func TestVMessOutbound(t *testing.T) { }, }, }, + { + Input: `{ + "address": "127.0.0.1", + "port": 80, + "id": "e641f5ad-9397-41e3-bf1a-e8740dfed019", + "email": "love@example.com", + "level": 255 + }`, + Parser: loadJSON(creator), + Output: &outbound.Config{ + Receiver: []*protocol.ServerEndpoint{ + { + Address: &net.IPOrDomain{ + Address: &net.IPOrDomain_Ip{ + Ip: []byte{127, 0, 0, 1}, + }, + }, + Port: 80, + User: []*protocol.User{ + { + Email: "love@example.com", + Level: 255, + Account: serial.ToTypedMessage(&vmess.Account{ + Id: "e641f5ad-9397-41e3-bf1a-e8740dfed019", + SecuritySettings: &protocol.SecurityConfig{ + Type: protocol.SecurityType_AUTO, + }, + }), + }, + }, + }, + }, + }, + }, }) }