From 221cac77c1cef04bddb64f24f55f660f18b7b4b6 Mon Sep 17 00:00:00 2001 From: Yuwei Ba Date: Thu, 9 Jan 2025 05:35:54 +1100 Subject: [PATCH] support ss altport (#13) --- api/apimodel.go | 7 + api/fac/fac.go | 331 +------------------------- api/fac/model.go | 1 + config.yaml | 30 +++ service/controller/controller.go | 47 ++-- service/controller/inboundbuilder.go | 20 +- service/controller/outboundbuilder.go | 2 +- service/controller/userbuilder.go | 39 --- 8 files changed, 78 insertions(+), 399 deletions(-) create mode 100644 config.yaml diff --git a/api/apimodel.go b/api/apimodel.go index 2f7891b2..32237d4c 100644 --- a/api/apimodel.go +++ b/api/apimodel.go @@ -2,6 +2,7 @@ package api import ( "encoding/json" + "fmt" "regexp" "github.com/xtls/xray-core/infra/conf" @@ -62,6 +63,7 @@ type NodeInfo struct { NodeType string // Must be V2ray, Trojan, and Shadowsocks NodeID string Port uint32 + AltPort uint16 // AltPort is used for Shadowsocks-Plugin SpeedLimit uint64 // Bps AlterID uint16 TransportProtocol string @@ -100,6 +102,11 @@ type NodeInfo struct { RejectUnknownSni bool } +func (n *NodeInfo) Tag(listenIP string, port uint32) string { + return fmt.Sprintf("%s_%s_%d", n.NodeType, listenIP, port) + +} + type UserInfo struct { UID int Email string diff --git a/api/fac/fac.go b/api/fac/fac.go index 1cec0c1a..5ea81c3b 100644 --- a/api/fac/fac.go +++ b/api/fac/fac.go @@ -10,7 +10,6 @@ import ( "reflect" "regexp" "strconv" - "strings" "sync" "time" @@ -21,12 +20,6 @@ import ( "github.com/XrayR-project/XrayR/api" ) -var ( - firstPortRe = regexp.MustCompile(`(?m)port=(?P\d+)#?`) // First Port - secondPortRe = regexp.MustCompile(`(?m)port=\d+#(\d+)`) // Second Port - hostRe = regexp.MustCompile(`(?m)host=([\w.]+)\|?`) // Host -) - // APIClient create a api client to the panel. type APIClient struct { client *resty.Client @@ -188,42 +181,13 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) { return nil, fmt.Errorf("unmarshal %s failed: %w", reflect.TypeOf(nodeInfoResponse), err) } - // determine ssPanel version, if disable custom config or version < 2021.11, then use old api c.version = nodeInfoResponse.Version - var isExpired bool - if compareVersion(c.version, "2021.11") == -1 { - isExpired = true - } - - if c.DisableCustomConfig || isExpired { - if isExpired { - log.Print("The panel version is expired, it is recommended to update immediately") - } - - switch c.NodeType { - case "V2ray": - nodeInfo, err = c.ParseV2rayNodeResponse(nodeInfoResponse) - case "Trojan": - nodeInfo, err = c.ParseTrojanNodeResponse(nodeInfoResponse) - case "Shadowsocks": - nodeInfo, err = c.ParseSSNodeResponse(nodeInfoResponse) - case "Shadowsocks-Plugin": - nodeInfo, err = c.ParseSSPluginNodeResponse(nodeInfoResponse) - default: - return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType) - } - } else { - nodeInfo, err = c.ParseSSPanelNodeInfo(nodeInfoResponse) - if err != nil { - res, _ := json.Marshal(nodeInfoResponse) - return nil, fmt.Errorf("parse node info failed: %s, \nError: %s, \nPlease check the doc of custom_config for help: "+ - "https://xrayr-project.github.io/XrayR-doc/dui-jie-sspanel/sspanel/sspanel_custom_config", string(res), err) - } - } + nodeInfo, err = c.ParseSSPanelNodeInfo(nodeInfoResponse) if err != nil { res, _ := json.Marshal(nodeInfoResponse) - return nil, fmt.Errorf("parse node info failed: %s, \nError: %w", string(res), err) + return nil, fmt.Errorf("parse node info failed: %s, \nError: %s, \nPlease check the doc of custom_config for help: "+ + "https://xrayr-project.github.io/XrayR-doc/dui-jie-sspanel/sspanel/sspanel_custom_config", string(res), err) } return nodeInfo, nil @@ -407,292 +371,6 @@ func (c *APIClient) ReportIllegal(detectResultList *[]api.DetectResult) error { return nil } -// ParseV2rayNodeResponse parse the response for the given node info format -func (c *APIClient) ParseV2rayNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) { - var enableTLS bool - var path, host, transportProtocol, serviceName, HeaderType string - var header json.RawMessage - var speedLimit uint64 - - if nodeInfoResponse.RawServerString == "" { - return nil, fmt.Errorf("no server info in response") - } - serverConf := strings.Split(nodeInfoResponse.RawServerString, ";") - - parsedPort, err := strconv.ParseInt(serverConf[1], 10, 32) - if err != nil { - return nil, err - } - if parsedPort < 0 || parsedPort > math.MaxUint32 { - return nil, fmt.Errorf("parsed port %d is out of range for uint32", parsedPort) - } - port := uint32(parsedPort) - - parsedAlterID, err := strconv.ParseInt(serverConf[2], 10, 16) - if err != nil { - return nil, err - } - if parsedAlterID < 0 || parsedAlterID > math.MaxUint16 { - return nil, fmt.Errorf("parsed alterID %d is out of range for uint16", parsedAlterID) - } - alterID := uint16(parsedAlterID) - - // Compatible with more node types config - for _, value := range serverConf[3:5] { - switch value { - case api.SecurityTypeTLS: - enableTLS = true - default: - if value != "" { - transportProtocol = value - } - } - } - extraServerConf := strings.Split(serverConf[5], "|") - serviceName = "" - for _, item := range extraServerConf { - conf := strings.Split(item, "=") - key := conf[0] - if key == "" { - continue - } - value := conf[1] - switch key { - case "path": - rawPath := strings.Join(conf[1:], "=") // In case of the path strings contains the "=" - path = rawPath - case "host": - host = value - case "servicename": - serviceName = value - case "headerType": - HeaderType = value - } - } - - if c.SpeedLimit > 0 { - speedLimit = uint64((c.SpeedLimit * 1000000) / 8) - } else { - speedLimit = uint64((nodeInfoResponse.SpeedLimit * 1000000) / 8) - } - - if HeaderType != "" { - headers := map[string]string{"type": HeaderType} - header, err = json.Marshal(headers) - } - - if err != nil { - return nil, fmt.Errorf("marshal Header Type %s into config failed: %w", header, err) - } - - // Create GeneralNodeInfo - nodeInfo := &api.NodeInfo{ - NodeType: c.NodeType, - NodeID: c.NodeID, - Port: port, - SpeedLimit: speedLimit, - AlterID: alterID, - TransportProtocol: transportProtocol, - EnableTLS: enableTLS, - Path: path, - Host: host, - EnableVless: c.EnableVless, - VlessFlow: c.VlessFlow, - ServiceName: serviceName, - Header: header, - } - - return nodeInfo, nil -} - -// ParseSSNodeResponse parse the response for the given node info format -func (c *APIClient) ParseSSNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) { - var port uint32 = 0 - var speedLimit uint64 - var method string - path := "/mod_mu/users" - res, err := c.client.R(). - SetQueryParam("node_id", c.NodeID). - SetResult(&Response{}). - ForceContentType("application/json"). - Get(path) - - response, err := c.parseResponse(res, path, err) - if err != nil { - return nil, err - } - - userListResponse := new([]UserResponse) - - if err := json.Unmarshal(response.Data, userListResponse); err != nil { - return nil, fmt.Errorf("unmarshal %s failed: %w", reflect.TypeOf(userListResponse), err) - } - - // init server port - if len(*userListResponse) != 0 { - port = (*userListResponse)[0].Port - } - - if c.SpeedLimit > 0 { - speedLimit = uint64((c.SpeedLimit * 1000000) / 8) - } else { - speedLimit = uint64((nodeInfoResponse.SpeedLimit * 1000000) / 8) - } - // Create GeneralNodeInfo - nodeInfo := &api.NodeInfo{ - NodeType: c.NodeType, - NodeID: c.NodeID, - Port: port, - SpeedLimit: speedLimit, - TransportProtocol: "tcp", - CypherMethod: method, - } - - return nodeInfo, nil -} - -// ParseSSPluginNodeResponse parse the response for the given node info format -func (c *APIClient) ParseSSPluginNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) { - var enableTLS bool - var path, host, transportProtocol string - var speedLimit uint64 - - serverConf := strings.Split(nodeInfoResponse.RawServerString, ";") - parsedPort, err := strconv.ParseInt(serverConf[1], 10, 32) - if err != nil { - return nil, err - } - if parsedPort < 0 || parsedPort > math.MaxUint32 { - return nil, fmt.Errorf("parsed port %d is out of range for uint32", parsedPort) - } - port := uint32(parsedPort) - port-- // Shadowsocks-Plugin requires two ports, one for ss the other for other stream protocol - if port <= 0 { - return nil, fmt.Errorf("Shadowsocks-Plugin listen port must bigger than 1") - } - // Compatible with more node types config - for _, value := range serverConf[3:5] { - switch value { - case "tls": - enableTLS = true - case "ws": - transportProtocol = api.TransportProtocolWS - case "obfs": - transportProtocol = api.TransportProtocolTCP - } - } - - extraServerConf := strings.Split(serverConf[5], "|") - for _, item := range extraServerConf { - conf := strings.Split(item, "=") - key := conf[0] - if key == "" { - continue - } - value := conf[1] - switch key { - case "path": - rawPath := strings.Join(conf[1:], "=") // In case of the path strings contains the "=" - path = rawPath - case "host": - host = value - } - } - if c.SpeedLimit > 0 { - speedLimit = uint64((c.SpeedLimit * 1000000) / 8) - } else { - speedLimit = uint64((nodeInfoResponse.SpeedLimit * 1000000) / 8) - } - - // Create GeneralNodeInfo - nodeInfo := &api.NodeInfo{ - NodeType: c.NodeType, - NodeID: c.NodeID, - Port: port, - SpeedLimit: speedLimit, - TransportProtocol: transportProtocol, - EnableTLS: enableTLS, - Path: path, - Host: host, - } - - return nodeInfo, nil -} - -// ParseTrojanNodeResponse parse the response for the given node info format -func (c *APIClient) ParseTrojanNodeResponse(nodeInfoResponse *NodeInfoResponse) (*api.NodeInfo, error) { - // 域名或IP;port=连接端口#偏移端口|host=xx - // gz.aaa.com;port=443#12345|host=hk.aaa.com - var p, host, outsidePort, insidePort, transportProtocol, serviceName string - var speedLimit uint64 - - if nodeInfoResponse.RawServerString == "" { - return nil, fmt.Errorf("no server info in response") - } - if result := firstPortRe.FindStringSubmatch(nodeInfoResponse.RawServerString); len(result) > 1 { - outsidePort = result[1] - } - if result := secondPortRe.FindStringSubmatch(nodeInfoResponse.RawServerString); len(result) > 1 { - insidePort = result[1] - } - if result := hostRe.FindStringSubmatch(nodeInfoResponse.RawServerString); len(result) > 1 { - host = result[1] - } - - if insidePort != "" { - p = insidePort - } else { - p = outsidePort - } - - parsedPort, err := strconv.ParseInt(p, 10, 32) - if err != nil { - return nil, err - } - if parsedPort < 0 || parsedPort > math.MaxUint32 { - return nil, fmt.Errorf("parsed port %d is out of range for uint32", parsedPort) - } - port := uint32(parsedPort) - - serverConf := strings.Split(nodeInfoResponse.RawServerString, ";") - extraServerConf := strings.Split(serverConf[1], "|") - transportProtocol = api.TransportProtocolTCP - serviceName = "" - for _, item := range extraServerConf { - conf := strings.Split(item, "=") - key := conf[0] - if key == "" { - continue - } - value := conf[1] - switch key { - case "grpc": - transportProtocol = api.TransportProtocolGRPC - case "servicename": - serviceName = value - } - } - - if c.SpeedLimit > 0 { - speedLimit = uint64((c.SpeedLimit * 1000000) / 8) - } else { - speedLimit = uint64((nodeInfoResponse.SpeedLimit * 1000000) / 8) - } - // Create GeneralNodeInfo - nodeInfo := &api.NodeInfo{ - NodeType: c.NodeType, - NodeID: c.NodeID, - Port: port, - SpeedLimit: speedLimit, - TransportProtocol: transportProtocol, - EnableTLS: true, - Host: host, - ServiceName: serviceName, - } - - return nodeInfo, nil -} - // ParseUserListResponse parse the response for the given node info format func (c *APIClient) ParseUserListResponse(userInfoResponse *[]UserResponse) (*[]api.UserInfo, error) { c.access.Lock() @@ -787,7 +465,7 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a port := uint32(parsedPort) switch c.NodeType { - case "Shadowsocks": + case api.NodeTypeShadowsocks, api.NodeTypeShadowsocksPlugin: transportProtocol = "tcp" case "V2ray": transportProtocol = nodeConfig.Network @@ -831,6 +509,7 @@ func (c *APIClient) ParseSSPanelNodeInfo(nodeInfoResponse *NodeInfoResponse) (*a NodeType: c.NodeType, NodeID: c.NodeID, Port: port, + AltPort: nodeConfig.AltPort, SpeedLimit: speedLimit, AlterID: alterID, TransportProtocol: transportProtocol, diff --git a/api/fac/model.go b/api/fac/model.go index 9e12d645..da56cbc5 100644 --- a/api/fac/model.go +++ b/api/fac/model.go @@ -17,6 +17,7 @@ type NodeInfoResponse struct { type CustomConfig struct { OffsetPortNode string `json:"offset_port_node"` + AltPort uint16 `json:"alt_port"` Host string `json:"host"` Method string `json:"method"` TLS string `json:"tls"` diff --git a/config.yaml b/config.yaml new file mode 100644 index 00000000..644d639f --- /dev/null +++ b/config.yaml @@ -0,0 +1,30 @@ +Log: + Level: debug # Log level: none, error, warning, info, debug + AccessPath: access.log + ErrorPath: error.log +# InboundConfigPath: custom_inbound.json +ConnectionConfig: + Handshake: 4 # Handshake time limit, Second + ConnIdle: 10 # Connection idle time limit, Second + UplinkOnly: 2 # Time limit when the connection downstream is closed, Second + DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second + BufferSize: 64 # The internal cache size of each connection, kB +Nodes: + - PanelType: "FAC" + ApiConfig: + ApiHost: http://localhost:3000 + ApiKey: "ss123" + NodeID: test-node-westus-01.dev.slow-access.work + NodeType: Shadowsocks-Plugin # Node type: V2ray, Trojan, Shadowsocks, Shadowsocks-Plugin + Timeout: 30 # Timeout for the api request + ControllerConfig: + ListenIP: 0.0.0.0 # local listen address + SendIP: 0.0.0.0 # outbound interface ip + UpdatePeriodic: 60 # Time to update the nodeinfo, how many sec. + EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well + DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy + DisableUploadTraffic: false # Disable Upload Traffic to the panel + DisableGetRule: true # Disable Get Rule from the panel + DisableIVCheck: false # Disable the anti-reply protection for Shadowsocks + DisableSniffing: true # Disable domain sniffing + EnableProxyProtocol: false diff --git a/service/controller/controller.go b/service/controller/controller.go index f7f36025..8d188976 100644 --- a/service/controller/controller.go +++ b/service/controller/controller.go @@ -87,7 +87,7 @@ func (c *Controller) Start() error { return errors.New("server port must > 0") } c.nodeInfo = newNodeInfo - c.Tag = c.buildNodeTag() + c.Tag = newNodeInfo.Tag(c.config.ListenIP, c.nodeInfo.Port) // Add new tag err = c.addNewTag(newNodeInfo) @@ -241,7 +241,7 @@ func (c *Controller) nodeInfoMonitor() (err error) { } // Add new tag c.nodeInfo = newNodeInfo - c.Tag = c.buildNodeTag() + c.Tag = newNodeInfo.Tag(c.config.ListenIP, newNodeInfo.Port) err = c.addNewTag(newNodeInfo) if err != nil { c.logger.Print(err) @@ -353,9 +353,10 @@ func (c *Controller) addNewTag(newNodeInfo *api.NodeInfo) (err error) { } func (c *Controller) addInboundForSSPlugin(newNodeInfo api.NodeInfo) (err error) { //nolint:gocritic // ignore - // Shadowsocks-Plugin require a separate inbound for other TransportProtocol likes: ws, grpc + // Add a local Shadowsocks for obfs fakeNodeInfo := newNodeInfo fakeNodeInfo.TransportProtocol = api.TransportProtocolTCP + fakeNodeInfo.NodeType = api.NodeTypeShadowsocks fakeNodeInfo.EnableTLS = false // Add a regular Shadowsocks inbound and outbound inboundConfig, err := InboundBuilder(c.config, &fakeNodeInfo, c.Tag) @@ -374,12 +375,11 @@ func (c *Controller) addInboundForSSPlugin(newNodeInfo api.NodeInfo) (err error) if err != nil { return err } - // Add an inbound for upper streaming protocol + // Add a public UDP inbound fakeNodeInfo = newNodeInfo - fakeNodeInfo.Port++ - fakeNodeInfo.NodeType = api.NodeTypeDokodemo - dokodemoTag := fmt.Sprintf("dokodemo-door_%s+1", c.Tag) - inboundConfig, err = InboundBuilder(c.config, &fakeNodeInfo, dokodemoTag) + fakeNodeInfo.NodeType = api.NodeTypeShadowsocksPlugin + tag := fakeNodeInfo.Tag(c.config.ListenIP, uint32(c.nodeInfo.AltPort)) + inboundConfig, err = InboundBuilder(c.config, &fakeNodeInfo, tag) if err != nil { return err } @@ -387,14 +387,6 @@ func (c *Controller) addInboundForSSPlugin(newNodeInfo api.NodeInfo) (err error) if err != nil { return err } - outBoundConfig, err = OutboundBuilder(c.config, &fakeNodeInfo, dokodemoTag) - if err != nil { - return err - } - err = c.addOutbound(outBoundConfig) - if err != nil { - return err - } return nil } @@ -409,19 +401,24 @@ func (c *Controller) addNewUser(userInfo *[]api.UserInfo, nodeInfo *api.NodeInfo } case api.NodeTypeTrojan: users = c.buildTrojanUser(userInfo) - case api.NodeTypeShadowsocks: + case api.NodeTypeShadowsocks, api.NodeTypeShadowsocksPlugin: users = c.buildSSUser(userInfo, nodeInfo.CypherMethod) - case api.NodeTypeShadowsocksPlugin: - users = c.buildSSPluginUser(userInfo) default: return fmt.Errorf("unsupported node type: %s", nodeInfo.NodeType) } - err = c.addUsers(users, c.Tag) - if err != nil { - return err + tags := []string{c.Tag} + if nodeInfo.NodeType == api.NodeTypeShadowsocksPlugin { + tags = append(tags, nodeInfo.Tag(c.config.ListenIP, uint32(nodeInfo.AltPort))) + } + for _, tag := range tags { + err = c.addUsers(users, tag) + if err != nil { + return err + } + c.logger.Printf("Added %d new users for tag %s", len(*userInfo), tag) + } - c.logger.Printf("Added %d new users", len(*userInfo)) return nil } @@ -608,10 +605,6 @@ func (c *Controller) userInfoMonitor() (err error) { return nil } -func (c *Controller) buildNodeTag() string { - return fmt.Sprintf("%s_%s_%d", c.nodeInfo.NodeType, c.config.ListenIP, c.nodeInfo.Port) -} - // func (c *Controller) logPrefix() string { // return fmt.Sprintf("[%s] %s(ID=%d)", c.clientInfo.APIHost, c.nodeInfo.NodeType, c.nodeInfo.NodeID) // } diff --git a/service/controller/inboundbuilder.go b/service/controller/inboundbuilder.go index 1e4da400..b7790163 100644 --- a/service/controller/inboundbuilder.go +++ b/service/controller/inboundbuilder.go @@ -23,7 +23,7 @@ import ( func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.InboundHandlerConfig, error) { inboundDetourConfig := &conf.InboundDetourConfig{} // Build Listen IP address - if nodeInfo.NodeType == "Shadowsocks-Plugin" { + if nodeInfo.NodeType == api.NodeTypeShadowsocks { // Shdowsocks listen in 127.0.0.1 for safety inboundDetourConfig.ListenOn = &conf.Address{Address: net.ParseAddress("127.0.0.1")} } else if config.ListenIP != "" { @@ -32,8 +32,12 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I } // Build Port + port := nodeInfo.Port + if nodeInfo.NodeType == api.NodeTypeShadowsocksPlugin { + port = uint32(nodeInfo.AltPort) + } portList := &conf.PortList{ - Range: []conf.PortRange{{From: nodeInfo.Port, To: nodeInfo.Port}}, + Range: []conf.PortRange{{From: port, To: port}}, } inboundDetourConfig.PortList = portList // Build Tag @@ -57,8 +61,8 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I var proxySetting any // Build Protocol and Protocol setting switch nodeInfo.NodeType { - case "V2ray", "Vmess", "Vless": - if nodeInfo.EnableVless || (nodeInfo.NodeType == "Vless" && nodeInfo.NodeType != "Vmess") { + case api.NodeTypeV2ray, api.NodeTypeVLess, api.NodeTypeVMESS: + if nodeInfo.EnableVless || (nodeInfo.NodeType == api.NodeTypeVLess && nodeInfo.NodeType != api.NodeTypeVMESS) { protocol = "vless" // Enable fallback if config.EnableFallback { @@ -121,7 +125,11 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I proxySetting.Password = randPasswd } - proxySetting.NetworkList = &conf.NetworkList{"tcp", "udp"} + if nodeInfo.NodeType == api.NodeTypeShadowsocks { + proxySetting.NetworkList = &conf.NetworkList{"tcp", "udp"} + } else { + proxySetting.NetworkList = &conf.NetworkList{"udp"} + } proxySetting.IVCheck = true if config.DisableIVCheck { proxySetting.IVCheck = false @@ -134,7 +142,7 @@ func InboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core.I NetworkList []string `json:"network"` }{ Host: "v1.mux.cool", - NetworkList: []string{"tcp", "udp"}, + NetworkList: []string{"udp"}, } default: return nil, fmt.Errorf("unsupported node type: %s, Only support: V2ray, Trojan, Shadowsocks, and Shadowsocks-Plugin", nodeInfo.NodeType) diff --git a/service/controller/outboundbuilder.go b/service/controller/outboundbuilder.go index 8423e1b6..87cc8c63 100644 --- a/service/controller/outboundbuilder.go +++ b/service/controller/outboundbuilder.go @@ -33,7 +33,7 @@ func OutboundBuilder(config *Config, nodeInfo *api.NodeInfo, tag string) (*core. } // Used for Shadowsocks-Plugin if nodeInfo.NodeType == "dokodemo-door" { - proxySetting.Redirect = fmt.Sprintf("127.0.0.1:%d", nodeInfo.Port-1) + proxySetting.Redirect = fmt.Sprintf("127.0.0.1:%d", nodeInfo.Port) } var setting json.RawMessage setting, err := json.Marshal(proxySetting) diff --git a/service/controller/userbuilder.go b/service/controller/userbuilder.go index 375080b9..9ac2b919 100644 --- a/service/controller/userbuilder.go +++ b/service/controller/userbuilder.go @@ -109,45 +109,6 @@ func (c *Controller) buildSSUser(userInfo *[]api.UserInfo, method string) (users return users } -func (c *Controller) buildSSPluginUser(userInfo *[]api.UserInfo) (users []*protocol.User) { - users = make([]*protocol.User, len(*userInfo)) - - for i, user := range *userInfo { - // shadowsocks2022 Key = openssl rand -base64 32 and multi users needn't cipher method - if C.Contains(shadowaead_2022.List, strings.ToLower(user.Method)) { - e := c.buildUserTag(&user) - userKey, err := c.checkShadowsocksPassword(user.Passwd, user.Method) - if err != nil { - errors.LogError(context.Background(), "[UID: %d] %s", user.UID, err) - continue - } - users[i] = &protocol.User{ - Level: 0, - Email: e, - Account: serial.ToTypedMessage(&shadowsocks_2022.User{ - Key: userKey, - Email: e, - Level: 0, - }), - } - } else { - // Check if the cypher method is AEAD - cypherMethod := cipherFromString(user.Method) - if _, ok := AEADMethod[cypherMethod]; ok { - users[i] = &protocol.User{ - Level: 0, - Email: c.buildUserTag(&user), - Account: serial.ToTypedMessage(&shadowsocks.Account{ - Password: user.Passwd, - CipherType: cypherMethod, - }), - } - } - } - } - return users -} - func cipherFromString(c string) shadowsocks.CipherType { switch strings.ToLower(c) { case "aes-128-gcm", "aead_aes_128_gcm":