2020-11-25 19:01:53 +08:00
package conf
import (
"encoding/json"
"strings"
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"
2026-05-02 16:32:59 +03:00
"github.com/xtls/xray-core/common/task"
2021-01-12 11:31:02 +00:00
"github.com/xtls/xray-core/common/uuid"
2020-12-04 09:36:16 +08:00
"github.com/xtls/xray-core/proxy/vmess"
"github.com/xtls/xray-core/proxy/vmess/inbound"
"github.com/xtls/xray-core/proxy/vmess/outbound"
2023-08-10 04:43:34 +00:00
"google.golang.org/protobuf/proto"
2020-11-25 19:01:53 +08:00
)
type VMessAccount struct {
2021-04-29 06:29:42 +08:00
ID string `json:"id"`
Security string `json:"security"`
Experiments string `json:"experiments"`
2020-11-25 19:01:53 +08:00
}
// Build implements Buildable
func ( a * VMessAccount ) Build () * vmess . Account {
var st protocol . SecurityType
switch strings . ToLower ( a . Security ) {
case "aes-128-gcm" :
st = protocol . SecurityType_AES128_GCM
case "chacha20-poly1305" :
st = protocol . SecurityType_CHACHA20_POLY1305
case "auto" :
st = protocol . SecurityType_AUTO
default :
st = protocol . SecurityType_AUTO
}
return & vmess . Account {
2023-06-18 17:42:17 +00:00
Id : a . ID ,
2020-11-25 19:01:53 +08:00
SecuritySettings : & protocol . SecurityConfig {
Type : st ,
},
2021-04-29 06:29:42 +08:00
TestsEnabled : a . Experiments ,
2020-11-25 19:01:53 +08:00
}
}
type VMessDefaultConfig struct {
2023-06-18 17:42:17 +00:00
Level byte `json:"level"`
2020-11-25 19:01:53 +08:00
}
// Build implements Buildable
func ( c * VMessDefaultConfig ) Build () * inbound . DefaultConfig {
config := new ( inbound . DefaultConfig )
config . Level = uint32 ( c . Level )
return config
}
type VMessInboundConfig struct {
2026-05-07 19:10:48 +08:00
Users [] json . RawMessage `json:"users"`
Clients [] json . RawMessage `json:"clients"`
2026-01-18 04:17:25 +00:00
Defaults * VMessDefaultConfig `json:"default"`
2020-11-25 19:01:53 +08:00
}
// Build implements Buildable
func ( c * VMessInboundConfig ) Build () ( proto . Message , error ) {
2026-01-23 23:45:20 +08:00
errors . PrintNonRemovalDeprecatedFeatureWarning ( "VMess (with no Forward Secrecy, etc.)" , "VLESS Encryption" )
2026-01-18 04:17:25 +00:00
2023-06-12 10:32:25 -04:00
config := & inbound . Config {}
2020-11-25 19:01:53 +08:00
if c . Defaults != nil {
config . Default = c . Defaults . Build ()
}
2026-05-07 19:10:48 +08:00
if c . Clients != nil {
c . Users = c . Clients
}
2020-11-25 19:01:53 +08:00
config . User = make ([] * protocol . User , len ( c . Users ))
2026-05-02 16:32:59 +03:00
processUser := func ( idx int ) error {
rawData := c . Users [ idx ]
2020-11-25 19:01:53 +08:00
user := new ( protocol . User )
if err := json . Unmarshal ( rawData , user ); err != nil {
2026-05-02 16:32:59 +03:00
return errors . New ( "invalid VMess user" ). Base ( err )
2020-11-25 19:01:53 +08:00
}
account := new ( VMessAccount )
if err := json . Unmarshal ( rawData , account ); err != nil {
2026-05-02 16:32:59 +03:00
return errors . New ( "invalid VMess user" ). Base ( err )
2020-11-25 19:01:53 +08:00
}
2021-01-12 11:31:02 +00:00
u , err := uuid . ParseString ( account . ID )
if err != nil {
2026-05-02 16:32:59 +03:00
return err
2021-01-12 11:31:02 +00:00
}
account . ID = u . String ()
2020-11-25 19:01:53 +08:00
user . Account = serial . ToTypedMessage ( account . Build ())
config . User [ idx ] = user
2026-05-02 16:32:59 +03:00
return nil
}
if err := task . ParallelForN ( len ( c . Users ), processUser ); err != nil {
return nil , err
2020-11-25 19:01:53 +08:00
}
return config , nil
}
type VMessOutboundTarget 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 VMessOutboundConfig struct {
2025-09-11 21:48:20 +08:00
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"`
2020-11-25 19:01:53 +08:00
}
// Build implements Buildable
func ( c * VMessOutboundConfig ) Build () ( proto . Message , error ) {
2026-01-23 23:45:20 +08:00
errors . PrintNonRemovalDeprecatedFeatureWarning ( "VMess (with no Forward Secrecy, etc.)" , "VLESS Encryption" )
2026-01-18 04:17:25 +00:00
2020-11-25 19:01:53 +08:00
config := new ( outbound . Config )
2025-09-11 21:48:20 +08:00
if c . Address != nil {
c . Receivers = [] * VMessOutboundTarget {
{
Address : c . Address ,
Port : c . Port ,
Users : [] json . RawMessage {{}},
},
}
}
2025-09-15 21:31:27 +08:00
if len ( c . Receivers ) != 1 {
return nil , errors . New ( `VMess settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VMess outbounds and routing balancer instead` )
2020-11-25 19:01:53 +08:00
}
2025-09-15 21:31:27 +08:00
for _ , rec := range c . Receivers {
if len ( rec . Users ) != 1 {
return nil , errors . New ( `VMess vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VMess outbounds and routing balancer instead` )
2020-11-25 19:01:53 +08:00
}
if rec . Address == nil {
2025-09-15 21:31:27 +08:00
return nil , errors . New ( `VMess vnext: "address" is not set` )
2020-11-25 19:01:53 +08:00
}
spec := & protocol . ServerEndpoint {
Address : rec . Address . Build (),
Port : uint32 ( rec . Port ),
}
for _ , rawUser := range rec . Users {
user := new ( protocol . User )
2025-09-11 21:48:20 +08:00
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 )
}
2020-11-25 19:01:53 +08:00
}
account := new ( VMessAccount )
2025-09-11 21:48:20 +08:00
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 )
}
2020-11-25 19:01:53 +08:00
}
2021-01-12 11:31:02 +00:00
u , err := uuid . ParseString ( account . ID )
if err != nil {
return nil , err
}
account . ID = u . String ()
2020-11-25 19:01:53 +08:00
user . Account = serial . ToTypedMessage ( account . Build ())
2025-09-15 21:31:27 +08:00
spec . User = user
break
2020-11-25 19:01:53 +08:00
}
2025-09-15 21:31:27 +08:00
config . Receiver = spec
break
2020-11-25 19:01:53 +08:00
}
return config , nil
}