Merge pull request #89 from Yuzuki616/dev

Dev
This commit is contained in:
Yuzuki 2023-07-15 18:13:51 +08:00 committed by GitHub
commit 720173f3f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 290 additions and 196 deletions

View File

@ -2,13 +2,16 @@ package panel
import (
"fmt"
"github.com/Yuzuki616/V2bX/conf"
"github.com/goccy/go-json"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/Yuzuki616/V2bX/common/crypt"
"github.com/Yuzuki616/V2bX/conf"
"github.com/goccy/go-json"
)
type CommonNodeRsp struct {
@ -97,7 +100,6 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
if err != nil {
return nil, fmt.Errorf("decode common params error: %s", err)
}
var extra []byte
for i := range common.Routes { // parse rules from routes
var matchs []string
if _, ok := common.Routes[i].Match.(string); ok {
@ -117,10 +119,6 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
node.Rules = append(node.Rules, regexp.MustCompile(v))
}
case "dns":
if matchs[0] != "extra" {
break
}
extra = []byte(strings.Join(matchs[1:], ""))
}
}
node.ServerName = common.ServerName
@ -142,11 +140,14 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
if rsp.Tls == 1 {
node.Tls = true
}
if len(extra) != 0 {
err = json.Unmarshal(extra, &node.ExtraConfig)
if err != nil {
return nil, fmt.Errorf("decode v2ray extra error: %s", err)
}
err = json.Unmarshal(rsp.NetworkSettings, &node.ExtraConfig)
if err != nil {
return nil, fmt.Errorf("decode v2ray extra error: %s", err)
}
if node.ExtraConfig.RealityConfig.PrivateKey != "" {
temp := crypt.GenShaHash([]byte(c.APIHost + c.Token))[:32]
temp, err = crypt.AesDecrypt(node.ExtraConfig.RealityConfig.PrivateKey, []byte(temp))
node.ExtraConfig.RealityConfig.PrivateKey = temp
}
case "shadowsocks":
rsp := ShadowsocksNodeRsp{}

View File

@ -3,14 +3,15 @@ package panel
import (
"bufio"
"fmt"
"github.com/Yuzuki616/V2bX/conf"
"github.com/go-resty/resty/v2"
"log"
"os"
"regexp"
"strconv"
"strings"
"time"
"github.com/Yuzuki616/V2bX/conf"
"github.com/go-resty/resty/v2"
)
// Panel is the interface for different panel's api.
@ -18,7 +19,7 @@ import (
type Client struct {
client *resty.Client
APIHost string
Key string
Token string
NodeType string
NodeId int
LocalRuleList []*regexp.Regexp
@ -48,7 +49,7 @@ func New(c *conf.ApiConfig) (*Client, error) {
default:
return nil, fmt.Errorf("unsupported Node type: %s", c.NodeType)
}
// Create Key for each requests
// set params
client.SetQueryParams(map[string]string{
"node_type": c.NodeType,
"node_id": strconv.Itoa(c.NodeID),
@ -58,7 +59,7 @@ func New(c *conf.ApiConfig) (*Client, error) {
localRuleList := readLocalRuleList(c.RuleListPath)
return &Client{
client: client,
Key: c.Key,
Token: c.Key,
APIHost: c.APIHost,
NodeType: c.NodeType,
NodeId: c.NodeID,

View File

@ -4,6 +4,9 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"strings"
"github.com/Yuzuki616/V2bX/common/crypt"
"github.com/spf13/cobra"
"golang.org/x/crypto/curve25519"
@ -22,6 +25,19 @@ func init() {
}
func executeX25519() {
var yes, key string
fmt.Println("要对私钥进行加密吗?(Y/n)")
fmt.Scan(&yes)
if strings.ToLower(yes) == "y" {
var temp string
fmt.Println("请输入Api接口地址:")
fmt.Scan(&temp)
key = temp
fmt.Println("请输入Api认证Token:")
fmt.Scan(&temp)
key += temp
key = crypt.GenShaHash([]byte(key))
}
var output string
var err error
defer func() {
@ -45,9 +61,16 @@ func executeX25519() {
output = Err("gen X25519 error: ", err)
return
}
p := base64.RawURLEncoding.EncodeToString(privateKey)
output = fmt.Sprint("Private key: ",
base64.RawURLEncoding.EncodeToString(privateKey),
p,
"\nPublic key: ",
base64.RawURLEncoding.EncodeToString(publicKey))
if strings.ToLower(yes) == "y" {
key, err = crypt.AesEncrypt([]byte(p), []byte(key[:32]))
if err != nil {
output = Err("encrypt private key error: ", err)
}
output += "\n加密后的Private key" + key
}
}

View File

@ -1,131 +0,0 @@
package builder
import (
"encoding/base64"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/trojan"
"github.com/xtls/xray-core/proxy/vless"
"strings"
)
func BuildVmessUsers(tag string, userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i, user := range userInfo {
users[i] = BuildVmessUser(tag, &user)
}
return users
}
func BuildVmessUser(tag string, userInfo *panel.UserInfo) (user *protocol.User) {
vmessAccount := &conf.VMessAccount{
ID: userInfo.Uuid,
AlterIds: 0,
Security: "auto",
}
return &protocol.User{
Level: 0,
Email: BuildUserTag(tag, userInfo.Uuid), // Uid: InboundTag|email
Account: serial.ToTypedMessage(vmessAccount.Build()),
}
}
func BuildVlessUsers(tag string, userInfo []panel.UserInfo, flow string) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = BuildVlessUser(tag, &(userInfo)[i], flow)
}
return users
}
func BuildVlessUser(tag string, userInfo *panel.UserInfo, flow string) (user *protocol.User) {
vlessAccount := &vless.Account{
Id: userInfo.Uuid,
}
vlessAccount.Flow = flow
return &protocol.User{
Level: 0,
Email: BuildUserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(vlessAccount),
}
}
func BuildTrojanUsers(tag string, userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = BuildTrojanUser(tag, &(userInfo)[i])
}
return users
}
func BuildTrojanUser(tag string, userInfo *panel.UserInfo) (user *protocol.User) {
trojanAccount := &trojan.Account{
Password: userInfo.Uuid,
}
return &protocol.User{
Level: 0,
Email: BuildUserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(trojanAccount),
}
}
func BuildSSUsers(tag string, userInfo []panel.UserInfo, cypher string, serverKey string) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = BuildSSUser(tag, &userInfo[i], cypher, serverKey)
}
return users
}
func BuildSSUser(tag string, userInfo *panel.UserInfo, cypher string, serverKey string) (user *protocol.User) {
if serverKey == "" {
ssAccount := &shadowsocks.Account{
Password: userInfo.Uuid,
CipherType: getCipherFromString(cypher),
}
return &protocol.User{
Level: 0,
Email: BuildUserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(ssAccount),
}
} else {
var keyLength int
switch cypher {
case "2022-blake3-aes-128-gcm":
keyLength = 16
case "2022-blake3-aes-256-gcm":
keyLength = 32
}
ssAccount := &shadowsocks_2022.User{
Key: base64.StdEncoding.EncodeToString([]byte(userInfo.Uuid[:keyLength])),
}
return &protocol.User{
Level: 0,
Email: BuildUserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(ssAccount),
}
}
}
func BuildUserTag(tag string, uuid string) string {
return fmt.Sprintf("%s|%s", tag, uuid)
}
func getCipherFromString(c string) shadowsocks.CipherType {
switch strings.ToLower(c) {
case "aes-128-gcm", "aead_aes_128_gcm":
return shadowsocks.CipherType_AES_128_GCM
case "aes-256-gcm", "aead_aes_256_gcm":
return shadowsocks.CipherType_AES_256_GCM
case "chacha20-poly1305", "aead_chacha20_poly1305", "chacha20-ietf-poly1305":
return shadowsocks.CipherType_CHACHA20_POLY1305
case "none", "plain":
return shadowsocks.CipherType_NONE
default:
return shadowsocks.CipherType_UNKNOWN
}
}

30
common/crypt/aes.go Normal file
View File

@ -0,0 +1,30 @@
package crypt
import (
"crypto/aes"
"encoding/base64"
)
func AesEncrypt(data []byte, key []byte) (string, error) {
a, err := aes.NewCipher(key)
if err != nil {
return "", err
}
en := make([]byte, len(data))
a.Encrypt(en, data)
return base64.StdEncoding.EncodeToString(en), nil
}
func AesDecrypt(data string, key []byte) (string, error) {
d, err := base64.StdEncoding.DecodeString(data)
if err != nil {
return "", err
}
a, err := aes.NewCipher(key)
if err != nil {
return "", err
}
de := make([]byte, len(data))
a.Decrypt(de, d)
return string(de), nil
}

11
common/crypt/sha.go Normal file
View File

@ -0,0 +1,11 @@
package crypt
import (
"crypto/sha256"
"encoding/hex"
)
func GenShaHash(data []byte) string {
d := sha256.Sum256(data)
return hex.EncodeToString(d[:])
}

9
common/format/user.go Normal file
View File

@ -0,0 +1,9 @@
package format
import (
"fmt"
)
func UserTag(tag string, uuid string) string {
return fmt.Sprintf("%s|%s", tag, uuid)
}

View File

@ -1,4 +1,4 @@
package builder
package xray
import (
"crypto/rand"
@ -6,7 +6,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/conf"
"github.com/goccy/go-json"
@ -16,7 +15,7 @@ import (
)
// BuildInbound build Inbound config for different protocol
func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) {
func buildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag string) (*core.InboundHandlerConfig, error) {
in := &coreConf.InboundDetourConfig{}
// Set network protocol
t := coreConf.TransportProtocol(nodeInfo.Network)
@ -102,24 +101,24 @@ func BuildInbound(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, tag s
RejectUnknownSNI: config.CertConfig.RejectUnknownSni,
}
}
}
// use remote reality replace local config
if nodeInfo.ExtraConfig.EnableReality {
rc := nodeInfo.ExtraConfig.RealityConfig
in.StreamSetting.Security = "reality"
d, err := json.Marshal(rc.Dest)
if err != nil {
return nil, fmt.Errorf("marshal reality dest error: %s", err)
}
in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{
Dest: d,
Xver: rc.Xver,
ServerNames: rc.ServerNames,
PrivateKey: rc.PrivateKey,
MinClientVer: rc.MinClientVer,
MaxClientVer: rc.MaxClientVer,
MaxTimeDiff: rc.MaxTimeDiff,
ShortIds: rc.ShortIds,
// use remote reality replace local config
if nodeInfo.ExtraConfig.EnableReality {
rc := nodeInfo.ExtraConfig.RealityConfig
in.StreamSetting.Security = "reality"
d, err := json.Marshal(rc.Dest)
if err != nil {
return nil, fmt.Errorf("marshal reality dest error: %s", err)
}
in.StreamSetting.REALITYSettings = &coreConf.REALITYConfig{
Dest: d,
Xver: rc.Xver,
ServerNames: rc.ServerNames,
PrivateKey: rc.PrivateKey,
MinClientVer: rc.MinClientVer,
MaxClientVer: rc.MaxClientVer,
MaxTimeDiff: rc.MaxTimeDiff,
ShortIds: rc.ShortIds,
}
}
}
// Support ProxyProtocol for any transport protocol
@ -194,6 +193,8 @@ func buildV2ray(config *conf.ControllerConfig, nodeInfo *panel.NodeInfo, inbound
if err != nil {
return fmt.Errorf("unmarshal grpc settings error: %s", err)
}
default:
return errors.New("the network type is not vail")
}
return nil
}

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/builder"
"github.com/Yuzuki616/V2bX/conf"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/features/inbound"
@ -12,7 +11,7 @@ import (
)
func (c *Core) AddNode(tag string, info *panel.NodeInfo, config *conf.ControllerConfig) error {
inboundConfig, err := builder.BuildInbound(config, info, tag)
inboundConfig, err := buildInbound(config, info, tag)
if err != nil {
return fmt.Errorf("build inbound error: %s", err)
}
@ -20,7 +19,7 @@ func (c *Core) AddNode(tag string, info *panel.NodeInfo, config *conf.Controller
if err != nil {
return fmt.Errorf("add inbound error: %s", err)
}
outBoundConfig, err := builder.BuildOutbound(config, tag)
outBoundConfig, err := buildOutbound(config, tag)
if err != nil {
return fmt.Errorf("build outbound error: %s", err)
}

View File

@ -1,4 +1,4 @@
package builder
package xray
import (
"fmt"
@ -10,7 +10,7 @@ import (
)
// BuildOutbound build freedom outbund config for addoutbound
func BuildOutbound(config *conf2.ControllerConfig, tag string) (*core.OutboundHandlerConfig, error) {
func buildOutbound(config *conf2.ControllerConfig, tag string) (*core.OutboundHandlerConfig, error) {
outboundDetourConfig := &conf.OutboundDetourConfig{}
outboundDetourConfig.Protocol = "freedom"
outboundDetourConfig.Tag = tag

65
core/xray/ss.go Normal file
View File

@ -0,0 +1,65 @@
package xray
import (
"encoding/base64"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/format"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"strings"
)
func buildSSUsers(tag string, userInfo []panel.UserInfo, cypher string, serverKey string) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = buildSSUser(tag, &userInfo[i], cypher, serverKey)
}
return users
}
func buildSSUser(tag string, userInfo *panel.UserInfo, cypher string, serverKey string) (user *protocol.User) {
if serverKey == "" {
ssAccount := &shadowsocks.Account{
Password: userInfo.Uuid,
CipherType: getCipherFromString(cypher),
}
return &protocol.User{
Level: 0,
Email: format.UserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(ssAccount),
}
} else {
var keyLength int
switch cypher {
case "2022-blake3-aes-128-gcm":
keyLength = 16
case "2022-blake3-aes-256-gcm":
keyLength = 32
}
ssAccount := &shadowsocks_2022.User{
Key: base64.StdEncoding.EncodeToString([]byte(userInfo.Uuid[:keyLength])),
}
return &protocol.User{
Level: 0,
Email: format.UserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(ssAccount),
}
}
}
func getCipherFromString(c string) shadowsocks.CipherType {
switch strings.ToLower(c) {
case "aes-128-gcm", "aead_aes_128_gcm":
return shadowsocks.CipherType_AES_128_GCM
case "aes-256-gcm", "aead_aes_256_gcm":
return shadowsocks.CipherType_AES_256_GCM
case "chacha20-poly1305", "aead_chacha20_poly1305", "chacha20-ietf-poly1305":
return shadowsocks.CipherType_CHACHA20_POLY1305
case "none", "plain":
return shadowsocks.CipherType_NONE
default:
return shadowsocks.CipherType_UNKNOWN
}
}

28
core/xray/trojan.go Normal file
View File

@ -0,0 +1,28 @@
package xray
import (
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/format"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/trojan"
)
func buildTrojanUsers(tag string, userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = buildTrojanUser(tag, &(userInfo)[i])
}
return users
}
func buildTrojanUser(tag string, userInfo *panel.UserInfo) (user *protocol.User) {
trojanAccount := &trojan.Account{
Password: userInfo.Uuid,
}
return &protocol.User{
Level: 0,
Email: format.UserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(trojanAccount),
}
}

View File

@ -4,7 +4,7 @@ import (
"context"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/builder"
"github.com/Yuzuki616/V2bX/common/format"
vCore "github.com/Yuzuki616/V2bX/core"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/proxy"
@ -33,7 +33,7 @@ func (c *Core) DelUsers(users []panel.UserInfo, tag string) error {
}
var up, down, user string
for i := range users {
user = builder.BuildUserTag(tag, users[i].Uuid)
user = format.UserTag(tag, users[i].Uuid)
err = userManager.RemoveUser(context.Background(), user)
if err != nil {
return err
@ -47,8 +47,8 @@ func (c *Core) DelUsers(users []panel.UserInfo, tag string) error {
}
func (c *Core) GetUserTraffic(tag, uuid string, reset bool) (up int64, down int64) {
upName := "user>>>" + builder.BuildUserTag(tag, uuid) + ">>>traffic>>>uplink"
downName := "user>>>" + builder.BuildUserTag(tag, uuid) + ">>>traffic>>>downlink"
upName := "user>>>" + format.UserTag(tag, uuid) + ">>>traffic>>>uplink"
downName := "user>>>" + format.UserTag(tag, uuid) + ">>>traffic>>>downlink"
upCounter := c.shm.GetCounter(upName)
downCounter := c.shm.GetCounter(downName)
if reset {
@ -77,22 +77,24 @@ func (c *Core) AddUsers(p *vCore.AddUsersParams) (added int, err error) {
p.NodeInfo.ExtraConfig.EnableVless {
if p.Config.XrayOptions.VlessFlow != "" {
if p.Config.XrayOptions.VlessFlow == p.NodeInfo.ExtraConfig.VlessFlow {
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.Config.XrayOptions.VlessFlow)
// local
users = buildVlessUsers(p.Tag, p.UserInfo, p.Config.XrayOptions.VlessFlow)
} else {
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow)
// remote
users = buildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow)
}
} else {
users = builder.BuildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow)
// remote
users = buildVlessUsers(p.Tag, p.UserInfo, p.NodeInfo.ExtraConfig.VlessFlow)
}
} else {
users = builder.BuildVmessUsers(p.Tag, p.UserInfo)
users = buildVmessUsers(p.Tag, p.UserInfo)
}
case "trojan":
users = builder.BuildTrojanUsers(p.Tag, p.UserInfo)
users = buildTrojanUsers(p.Tag, p.UserInfo)
case "shadowsocks":
users = builder.BuildSSUsers(p.Tag,
users = buildSSUsers(p.Tag,
p.UserInfo,
p.NodeInfo.Cipher,
p.NodeInfo.ServerKey)

51
core/xray/vmess.go Normal file
View File

@ -0,0 +1,51 @@
package xray
import (
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/format"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/proxy/vless"
)
func buildVmessUsers(tag string, userInfo []panel.UserInfo) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i, user := range userInfo {
users[i] = buildVmessUser(tag, &user)
}
return users
}
func buildVmessUser(tag string, userInfo *panel.UserInfo) (user *protocol.User) {
vmessAccount := &conf.VMessAccount{
ID: userInfo.Uuid,
AlterIds: 0,
Security: "auto",
}
return &protocol.User{
Level: 0,
Email: format.UserTag(tag, userInfo.Uuid), // Uid: InboundTag|email
Account: serial.ToTypedMessage(vmessAccount.Build()),
}
}
func buildVlessUsers(tag string, userInfo []panel.UserInfo, flow string) (users []*protocol.User) {
users = make([]*protocol.User, len(userInfo))
for i := range userInfo {
users[i] = buildVlessUser(tag, &(userInfo)[i], flow)
}
return users
}
func buildVlessUser(tag string, userInfo *panel.UserInfo, flow string) (user *protocol.User) {
vlessAccount := &vless.Account{
Id: userInfo.Uuid,
}
vlessAccount.Flow = flow
return &protocol.User{
Level: 0,
Email: format.UserTag(tag, userInfo.Uuid),
Account: serial.ToTypedMessage(vlessAccount),
}
}

View File

@ -2,7 +2,7 @@ package limiter
import (
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/builder"
"github.com/Yuzuki616/V2bX/common/format"
"time"
)
@ -11,7 +11,7 @@ func (l *Limiter) AddDynamicSpeedLimit(tag string, userInfo *panel.UserInfo, lim
DynamicSpeedLimit: limitNum,
ExpireTime: time.Now().Add(time.Duration(expire) * time.Second).Unix(),
}
l.UserLimitInfo.Store(builder.BuildUserTag(tag, userInfo.Uuid), userLimit)
l.UserLimitInfo.Store(format.UserTag(tag, userInfo.Uuid), userLimit)
return nil
}

View File

@ -4,7 +4,7 @@ import (
"errors"
"fmt"
"github.com/Yuzuki616/V2bX/api/panel"
"github.com/Yuzuki616/V2bX/common/builder"
"github.com/Yuzuki616/V2bX/common/format"
"github.com/Yuzuki616/V2bX/conf"
"github.com/juju/ratelimit"
log "github.com/sirupsen/logrus"
@ -61,7 +61,7 @@ func AddLimiter(tag string, l *conf.LimitConfig, users []panel.UserInfo) *Limite
SpeedLimit: users[i].SpeedLimit,
ExpireTime: 0,
}
info.UserLimitInfo.Store(builder.BuildUserTag(tag, users[i].Uuid), userLimit)
info.UserLimitInfo.Store(format.UserTag(tag, users[i].Uuid), userLimit)
}
}
limitLock.Lock()
@ -86,7 +86,7 @@ func UpdateLimiter(tag string, added []panel.UserInfo, deleted []panel.UserInfo)
return fmt.Errorf("get limit error: %s", err)
}
for i := range deleted {
l.UserLimitInfo.Delete(builder.BuildUserTag(tag, deleted[i].Uuid))
l.UserLimitInfo.Delete(format.UserTag(tag, deleted[i].Uuid))
}
for i := range added {
if added[i].SpeedLimit != 0 {
@ -95,7 +95,7 @@ func UpdateLimiter(tag string, added []panel.UserInfo, deleted []panel.UserInfo)
SpeedLimit: added[i].SpeedLimit,
ExpireTime: 0,
}
l.UserLimitInfo.Store(builder.BuildUserTag(tag, added[i].Uuid), userLimit)
l.UserLimitInfo.Store(format.UserTag(tag, added[i].Uuid), userLimit)
}
}
return nil

View File

@ -21,13 +21,17 @@ func (c *Controller) renewCertTask() {
}
func (c *Controller) requestCert() error {
if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" {
return fmt.Errorf("cert file path or key file path not exist")
}
switch c.CertConfig.CertMode {
case "reality", "none", "":
return nil
case "file":
if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" {
return fmt.Errorf("cert file path or key file path not exist")
}
case "dns", "http":
if c.CertConfig.CertFile == "" || c.CertConfig.KeyFile == "" {
return fmt.Errorf("cert file path or key file path not exist")
}
if file.IsExist(c.CertConfig.CertFile) && file.IsExist(c.CertConfig.KeyFile) {
return nil
}