|
|
@@ -37,6 +37,34 @@ type XrayAPI struct {
|
|
|
isConnected bool
|
|
|
}
|
|
|
|
|
|
+func getRequiredUserString(user map[string]any, key string) (string, error) {
|
|
|
+ value, ok := user[key]
|
|
|
+ if !ok || value == nil {
|
|
|
+ return "", fmt.Errorf("missing required user field %q", key)
|
|
|
+ }
|
|
|
+
|
|
|
+ strValue, ok := value.(string)
|
|
|
+ if !ok {
|
|
|
+ return "", fmt.Errorf("invalid type for user field %q: %T", key, value)
|
|
|
+ }
|
|
|
+
|
|
|
+ return strValue, nil
|
|
|
+}
|
|
|
+
|
|
|
+func getOptionalUserString(user map[string]any, key string) (string, error) {
|
|
|
+ value, ok := user[key]
|
|
|
+ if !ok || value == nil {
|
|
|
+ return "", nil
|
|
|
+ }
|
|
|
+
|
|
|
+ strValue, ok := value.(string)
|
|
|
+ if !ok {
|
|
|
+ return "", fmt.Errorf("invalid type for user field %q: %T", key, value)
|
|
|
+ }
|
|
|
+
|
|
|
+ return strValue, nil
|
|
|
+}
|
|
|
+
|
|
|
// Init connects to the Xray API server and initializes handler and stats service clients.
|
|
|
func (x *XrayAPI) Init(apiPort int) error {
|
|
|
if apiPort <= 0 || apiPort > math.MaxUint16 {
|
|
|
@@ -104,16 +132,36 @@ func (x *XrayAPI) DelInbound(tag string) error {
|
|
|
|
|
|
// AddUser adds a user to an inbound in the Xray core using the specified protocol and user data.
|
|
|
func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]any) error {
|
|
|
+ userEmail, err := getRequiredUserString(user, "email")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
var account *serial.TypedMessage
|
|
|
switch Protocol {
|
|
|
case "vmess":
|
|
|
+ userID, err := getRequiredUserString(user, "id")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
account = serial.ToTypedMessage(&vmess.Account{
|
|
|
- Id: user["id"].(string),
|
|
|
+ Id: userID,
|
|
|
})
|
|
|
case "vless":
|
|
|
+ userID, err := getRequiredUserString(user, "id")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ userFlow, err := getOptionalUserString(user, "flow")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
vlessAccount := &vless.Account{
|
|
|
- Id: user["id"].(string),
|
|
|
- Flow: user["flow"].(string),
|
|
|
+ Id: userID,
|
|
|
+ Flow: userFlow,
|
|
|
}
|
|
|
// Add testseed if provided
|
|
|
if testseedVal, ok := user["testseed"]; ok {
|
|
|
@@ -139,12 +187,27 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]an
|
|
|
}
|
|
|
account = serial.ToTypedMessage(vlessAccount)
|
|
|
case "trojan":
|
|
|
+ password, err := getRequiredUserString(user, "password")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
account = serial.ToTypedMessage(&trojan.Account{
|
|
|
- Password: user["password"].(string),
|
|
|
+ Password: password,
|
|
|
})
|
|
|
case "shadowsocks":
|
|
|
+ cipher, err := getOptionalUserString(user, "cipher")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ password, err := getRequiredUserString(user, "password")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
var ssCipherType shadowsocks.CipherType
|
|
|
- switch user["cipher"].(string) {
|
|
|
+ switch cipher {
|
|
|
case "aes-128-gcm":
|
|
|
ssCipherType = shadowsocks.CipherType_AES_128_GCM
|
|
|
case "aes-256-gcm":
|
|
|
@@ -159,18 +222,23 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]an
|
|
|
|
|
|
if ssCipherType != shadowsocks.CipherType_NONE {
|
|
|
account = serial.ToTypedMessage(&shadowsocks.Account{
|
|
|
- Password: user["password"].(string),
|
|
|
+ Password: password,
|
|
|
CipherType: ssCipherType,
|
|
|
})
|
|
|
} else {
|
|
|
account = serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
|
|
|
- Key: user["password"].(string),
|
|
|
- Email: user["email"].(string),
|
|
|
+ Key: password,
|
|
|
+ Email: userEmail,
|
|
|
})
|
|
|
}
|
|
|
case "hysteria":
|
|
|
+ auth, err := getRequiredUserString(user, "auth")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
account = serial.ToTypedMessage(&hysteriaAccount.Account{
|
|
|
- Auth: user["auth"].(string),
|
|
|
+ Auth: auth,
|
|
|
})
|
|
|
default:
|
|
|
return nil
|
|
|
@@ -178,11 +246,11 @@ func (x *XrayAPI) AddUser(Protocol string, inboundTag string, user map[string]an
|
|
|
|
|
|
client := *x.HandlerServiceClient
|
|
|
|
|
|
- _, err := client.AlterInbound(context.Background(), &command.AlterInboundRequest{
|
|
|
+ _, err = client.AlterInbound(context.Background(), &command.AlterInboundRequest{
|
|
|
Tag: inboundTag,
|
|
|
Operation: serial.ToTypedMessage(&command.AddUserOperation{
|
|
|
User: &protocol.User{
|
|
|
- Email: user["email"].(string),
|
|
|
+ Email: userEmail,
|
|
|
Account: account,
|
|
|
},
|
|
|
}),
|