Meow
2026-05-07 19:10:48 +08:00
committed by RPRX
parent 906d49a271
commit c42deab55c
14 changed files with 75 additions and 42 deletions

View File

@@ -23,6 +23,7 @@ func (v *HTTPAccount) Build() *http.Account {
} }
type HTTPServerConfig struct { type HTTPServerConfig struct {
Users []*HTTPAccount `json:"users"`
Accounts []*HTTPAccount `json:"accounts"` Accounts []*HTTPAccount `json:"accounts"`
Transparent bool `json:"allowTransparent"` Transparent bool `json:"allowTransparent"`
UserLevel uint32 `json:"userLevel"` UserLevel uint32 `json:"userLevel"`
@@ -34,9 +35,13 @@ func (c *HTTPServerConfig) Build() (proto.Message, error) {
UserLevel: c.UserLevel, UserLevel: c.UserLevel,
} }
if len(c.Accounts) > 0 { if c.Accounts != nil {
c.Users = c.Accounts
}
// TODO: PB
if len(c.Users) > 0 {
config.Accounts = make(map[string]string) config.Accounts = make(map[string]string)
for _, account := range c.Accounts { for _, account := range c.Users {
config.Accounts[account.Username] = account.Password config.Accounts[account.Username] = account.Password
} }
} }

View File

@@ -39,12 +39,16 @@ type HysteriaUserConfig struct {
type HysteriaServerConfig struct { type HysteriaServerConfig struct {
Version int32 `json:"version"` Version int32 `json:"version"`
Users []*HysteriaUserConfig `json:"clients"` Users []*HysteriaUserConfig `json:"users"`
Clients []*HysteriaUserConfig `json:"clients"`
} }
func (c *HysteriaServerConfig) Build() (proto.Message, error) { func (c *HysteriaServerConfig) Build() (proto.Message, error) {
config := new(hysteria.ServerConfig) config := new(hysteria.ServerConfig)
if c.Clients != nil {
c.Users = c.Clients
}
if len(c.Users) > 0 { if len(c.Users) > 0 {
config.Users = make([]*protocol.User, len(c.Users)) config.Users = make([]*protocol.User, len(c.Users))
processUser := func(idx int) error { processUser := func(idx int) error {

View File

@@ -45,13 +45,18 @@ type ShadowsocksServerConfig struct {
Password string `json:"password"` Password string `json:"password"`
Level byte `json:"level"` Level byte `json:"level"`
Email string `json:"email"` Email string `json:"email"`
Users []*ShadowsocksUserConfig `json:"clients"` Users []*ShadowsocksUserConfig `json:"users"`
Clients []*ShadowsocksUserConfig `json:"clients"`
NetworkList *NetworkList `json:"network"` NetworkList *NetworkList `json:"network"`
} }
func (v *ShadowsocksServerConfig) Build() (proto.Message, error) { func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption") errors.PrintNonRemovalDeprecatedFeatureWarning("Shadowsocks (with no Forward Secrecy, etc.)", "VLESS Encryption")
if v.Clients != nil {
v.Users = v.Clients
}
if C.Contains(shadowaead_2022.List, v.Cipher) { if C.Contains(shadowaead_2022.List, v.Cipher) {
return buildShadowsocks2022(v) return buildShadowsocks2022(v)
} }

View File

@@ -29,6 +29,7 @@ const (
type SocksServerConfig struct { type SocksServerConfig struct {
AuthMethod string `json:"auth"` AuthMethod string `json:"auth"`
Users []*SocksAccount `json:"users"`
Accounts []*SocksAccount `json:"accounts"` Accounts []*SocksAccount `json:"accounts"`
UDP bool `json:"udp"` UDP bool `json:"udp"`
Host *Address `json:"ip"` Host *Address `json:"ip"`
@@ -47,9 +48,13 @@ func (v *SocksServerConfig) Build() (proto.Message, error) {
config.AuthType = socks.AuthType_NO_AUTH config.AuthType = socks.AuthType_NO_AUTH
} }
if len(v.Accounts) > 0 { if v.Accounts != nil {
config.Accounts = make(map[string]string, len(v.Accounts)) v.Users = v.Accounts
for _, account := range v.Accounts { }
// TODO: PB
if len(v.Users) > 0 {
config.Accounts = make(map[string]string, len(v.Users))
for _, account := range v.Users {
config.Accounts[account.Username] = account.Password config.Accounts[account.Username] = account.Password
} }
} }

View File

@@ -112,6 +112,7 @@ type TrojanUserConfig struct {
// TrojanServerConfig is Inbound configuration // TrojanServerConfig is Inbound configuration
type TrojanServerConfig struct { type TrojanServerConfig struct {
Users []*TrojanUserConfig `json:"users"`
Clients []*TrojanUserConfig `json:"clients"` Clients []*TrojanUserConfig `json:"clients"`
Fallbacks []*TrojanInboundFallback `json:"fallbacks"` Fallbacks []*TrojanInboundFallback `json:"fallbacks"`
} }
@@ -120,12 +121,16 @@ type TrojanServerConfig struct {
func (c *TrojanServerConfig) Build() (proto.Message, error) { func (c *TrojanServerConfig) Build() (proto.Message, error) {
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed") errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
if c.Clients != nil {
c.Users = c.Clients
}
config := &trojan.ServerConfig{ config := &trojan.ServerConfig{
Users: make([]*protocol.User, len(c.Clients)), Users: make([]*protocol.User, len(c.Users)),
} }
processClient := func(idx int) error { processClient := func(idx int) error {
rawUser := c.Clients[idx] rawUser := c.Users[idx]
if rawUser.Flow != "" { if rawUser.Flow != "" {
return errors.PrintRemovedFeatureError(`Flow for Trojan`, ``) return errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
} }
@@ -139,7 +144,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
} }
return nil return nil
} }
if err := task.ParallelForN(len(c.Clients), processClient); err != nil { if err := task.ParallelForN(len(c.Users), processClient); err != nil {
return nil, err return nil, err
} }

View File

@@ -31,6 +31,7 @@ type VLessInboundFallback struct {
} }
type VLessInboundConfig struct { type VLessInboundConfig struct {
Users []json.RawMessage `json:"users"`
Clients []json.RawMessage `json:"clients"` Clients []json.RawMessage `json:"clients"`
Decryption string `json:"decryption"` Decryption string `json:"decryption"`
Fallbacks []*VLessInboundFallback `json:"fallbacks"` Fallbacks []*VLessInboundFallback `json:"fallbacks"`
@@ -41,21 +42,25 @@ type VLessInboundConfig struct {
// Build implements Buildable // Build implements Buildable
func (c *VLessInboundConfig) Build() (proto.Message, error) { func (c *VLessInboundConfig) Build() (proto.Message, error) {
config := new(inbound.Config) config := new(inbound.Config)
config.Clients = make([]*protocol.User, len(c.Clients))
if c.Clients != nil {
c.Users = c.Clients
}
config.Users = make([]*protocol.User, len(c.Users))
switch c.Flow { switch c.Flow {
case vless.XRV, "": case vless.XRV, "":
default: default:
return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`) return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
} }
processClient := func(idx int) error { processClient := func(idx int) error {
rawUser := c.Clients[idx] rawUser := c.Users[idx]
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if err := json.Unmarshal(rawUser, user); err != nil {
return errors.New(`VLESS clients: invalid user`).Base(err) return errors.New(`VLESS users: invalid user`).Base(err)
} }
account := new(vless.Account) account := new(vless.Account)
if err := json.Unmarshal(rawUser, account); err != nil { if err := json.Unmarshal(rawUser, account); err != nil {
return errors.New(`VLESS clients: invalid user`).Base(err) return errors.New(`VLESS users: invalid user`).Base(err)
} }
u, err := uuid.ParseString(account.Id) u, err := uuid.ParseString(account.Id)
@@ -69,7 +74,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
account.Flow = c.Flow account.Flow = c.Flow
case vless.XRV: case vless.XRV:
default: default:
return errors.New(`VLESS clients: "flow" doesn't support "` + account.Flow + `" in this version`) return errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)
} }
if len(account.Testseed) < 4 { if len(account.Testseed) < 4 {
@@ -77,24 +82,24 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
} }
if account.Encryption != "" { if account.Encryption != "" {
return errors.New(`VLESS clients: "encryption" should not be in inbound settings`) return errors.New(`VLESS users: "encryption" should not be in inbound settings`)
} }
if account.Reverse != nil { if account.Reverse != nil {
if account.Reverse.Tag == "" { if account.Reverse.Tag == "" {
return errors.New(`VLESS clients: "tag" can't be empty for "reverse"`) return errors.New(`VLESS users: "tag" can't be empty for "reverse"`)
} }
if account.Reverse.Sniffing != nil { // may not be reached: error json unmarshal if account.Reverse.Sniffing != nil { // may not be reached: error json unmarshal
return errors.New(`VLESS clients: inbound's "reverse" can't have "sniffing"`) return errors.New(`VLESS users: inbound's "reverse" can't have "sniffing"`)
} }
} }
user.Account = serial.ToTypedMessage(account) user.Account = serial.ToTypedMessage(account)
config.Clients[idx] = user config.Users[idx] = user
return nil return nil
} }
if err := task.ParallelForN(len(c.Clients), processClient); err != nil { if err := task.ParallelForN(len(c.Users), processClient); err != nil {
return nil, err return nil, err
} }

View File

@@ -119,7 +119,7 @@ func TestVLessInbound(t *testing.T) {
}`, }`,
Parser: loadJSON(creator), Parser: loadJSON(creator),
Output: &inbound.Config{ Output: &inbound.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: "27848739-7e62-4138-9fd3-098a63964b6b", Id: "27848739-7e62-4138-9fd3-098a63964b6b",

View File

@@ -59,7 +59,8 @@ func (c *VMessDefaultConfig) Build() *inbound.DefaultConfig {
} }
type VMessInboundConfig struct { type VMessInboundConfig struct {
Users []json.RawMessage `json:"clients"` Users []json.RawMessage `json:"users"`
Clients []json.RawMessage `json:"clients"`
Defaults *VMessDefaultConfig `json:"default"` Defaults *VMessDefaultConfig `json:"default"`
} }
@@ -73,6 +74,9 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
config.Default = c.Defaults.Build() config.Default = c.Defaults.Build()
} }
if c.Clients != nil {
c.Users = c.Clients
}
config.User = make([]*protocol.User, len(c.Users)) config.User = make([]*protocol.User, len(c.Users))
processUser := func(idx int) error { processUser := func(idx int) error {
rawData := c.Users[idx] rawData := c.Users[idx]

View File

@@ -80,7 +80,7 @@ func extractInboundUsers(inb *core.InboundHandlerConfig) []*protocol.User {
case *vmessin.Config: case *vmessin.Config:
return ty.User return ty.User
case *vlessin.Config: case *vlessin.Config:
return ty.Clients return ty.Users
case *trojan.ServerConfig: case *trojan.ServerConfig:
return ty.Users return ty.Users
case *shadowsocks.ServerConfig: case *shadowsocks.ServerConfig:

View File

@@ -108,7 +108,7 @@ func (x *Fallback) GetXver() uint64 {
type Config struct { type Config struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Clients []*protocol.User `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"` Users []*protocol.User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"` Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
Decryption string `protobuf:"bytes,3,opt,name=decryption,proto3" json:"decryption,omitempty"` Decryption string `protobuf:"bytes,3,opt,name=decryption,proto3" json:"decryption,omitempty"`
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"` XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
@@ -149,9 +149,9 @@ func (*Config) Descriptor() ([]byte, []int) {
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1} return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{1}
} }
func (x *Config) GetClients() []*protocol.User { func (x *Config) GetUsers() []*protocol.User {
if x != nil { if x != nil {
return x.Clients return x.Users
} }
return nil return nil
} }
@@ -209,9 +209,9 @@ const file_proxy_vless_inbound_config_proto_rawDesc = "" +
"\x04path\x18\x03 \x01(\tR\x04path\x12\x12\n" + "\x04path\x18\x03 \x01(\tR\x04path\x12\x12\n" +
"\x04type\x18\x04 \x01(\tR\x04type\x12\x12\n" + "\x04type\x18\x04 \x01(\tR\x04type\x12\x12\n" +
"\x04dest\x18\x05 \x01(\tR\x04dest\x12\x12\n" + "\x04dest\x18\x05 \x01(\tR\x04dest\x12\x12\n" +
"\x04xver\x18\x06 \x01(\x04R\x04xver\"\x96\x02\n" + "\x04xver\x18\x06 \x01(\x04R\x04xver\"\x92\x02\n" +
"\x06Config\x124\n" + "\x06Config\x120\n" +
"\aclients\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\aclients\x12@\n" + "\x05users\x18\x01 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x12@\n" +
"\tfallbacks\x18\x02 \x03(\v2\".xray.proxy.vless.inbound.FallbackR\tfallbacks\x12\x1e\n" + "\tfallbacks\x18\x02 \x03(\v2\".xray.proxy.vless.inbound.FallbackR\tfallbacks\x12\x1e\n" +
"\n" + "\n" +
"decryption\x18\x03 \x01(\tR\n" + "decryption\x18\x03 \x01(\tR\n" +
@@ -242,7 +242,7 @@ var file_proxy_vless_inbound_config_proto_goTypes = []any{
(*protocol.User)(nil), // 2: xray.common.protocol.User (*protocol.User)(nil), // 2: xray.common.protocol.User
} }
var file_proxy_vless_inbound_config_proto_depIdxs = []int32{ var file_proxy_vless_inbound_config_proto_depIdxs = []int32{
2, // 0: xray.proxy.vless.inbound.Config.clients:type_name -> xray.common.protocol.User 2, // 0: xray.proxy.vless.inbound.Config.users:type_name -> xray.common.protocol.User
0, // 1: xray.proxy.vless.inbound.Config.fallbacks:type_name -> xray.proxy.vless.inbound.Fallback 0, // 1: xray.proxy.vless.inbound.Config.fallbacks:type_name -> xray.proxy.vless.inbound.Fallback
2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for method input_type

View File

@@ -18,7 +18,7 @@ message Fallback {
} }
message Config { message Config {
repeated xray.common.protocol.User clients = 1; repeated xray.common.protocol.User users = 1;
repeated Fallback fallbacks = 2; repeated Fallback fallbacks = 2;
string decryption = 3; string decryption = 3;

View File

@@ -58,7 +58,7 @@ func init() {
c := config.(*Config) c := config.(*Config)
validator := new(vless.MemoryValidator) validator := new(vless.MemoryValidator)
for _, user := range c.Clients { for _, user := range c.Users {
u, err := user.ToMemoryUser() u, err := user.ToMemoryUser()
if err != nil { if err != nil {
return nil, errors.New("failed to get VLESS user").Base(err).AtError() return nil, errors.New("failed to get VLESS user").Base(err).AtError()

View File

@@ -54,7 +54,7 @@ func TestVless(t *testing.T) {
Listen: net.NewIPOrDomain(net.LocalHostIP), Listen: net.NewIPOrDomain(net.LocalHostIP),
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),
@@ -159,7 +159,7 @@ func TestVlessTls(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),
@@ -281,7 +281,7 @@ func TestVlessXtlsVision(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),
@@ -413,7 +413,7 @@ func TestVlessXtlsVisionReality(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),
@@ -553,7 +553,7 @@ func TestVlessRealityFingerprints(t *testing.T) {
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&inbound.Config{ ProxySettings: serial.ToTypedMessage(&inbound.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),

View File

@@ -267,7 +267,7 @@ func runVLESSRealityCase(t *testing.T, bin string, mode trafficMode, payloadSize
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&vin.Config{ ProxySettings: serial.ToTypedMessage(&vin.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),
@@ -501,7 +501,7 @@ func runVLesseEncCase(t *testing.T, bin string, mode trafficMode, payloadSize in
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&vin.Config{ ProxySettings: serial.ToTypedMessage(&vin.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),
@@ -605,7 +605,7 @@ func runVLESSXHTTPCase(t *testing.T, bin string, mode trafficMode, payloadSize i
}, },
}), }),
ProxySettings: serial.ToTypedMessage(&vin.Config{ ProxySettings: serial.ToTypedMessage(&vin.Config{
Clients: []*protocol.User{ Users: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vless.Account{ Account: serial.ToTypedMessage(&vless.Account{
Id: userID.String(), Id: userID.String(),