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"
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
case "none" :
st = protocol . SecurityType_NONE
2021-03-05 16:41:18 +08:00
case "zero" :
st = protocol . SecurityType_ZERO
2020-11-25 19:01:53 +08:00
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 {
Users [ ] json . RawMessage ` json:"clients" `
Defaults * VMessDefaultConfig ` json:"default" `
}
// Build implements Buildable
func ( c * VMessInboundConfig ) Build ( ) ( proto . Message , error ) {
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 ( )
}
config . User = make ( [ ] * protocol . User , len ( c . Users ) )
for idx , rawData := range c . Users {
user := new ( protocol . User )
if err := json . Unmarshal ( rawData , user ) ; err != nil {
2024-06-29 14:32:57 -04:00
return nil , 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 {
2024-06-29 14:32:57 -04:00
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 ( ) )
config . User [ idx ] = user
}
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 ) {
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
}