diff --git a/proxy/vmess/config/json/user.go b/proxy/vmess/config/json/user.go index 251cc622..6c0e4cdd 100644 --- a/proxy/vmess/config/json/user.go +++ b/proxy/vmess/config/json/user.go @@ -10,12 +10,14 @@ import ( type ConfigUser struct { Id *config.ID Email string + LevelValue config.UserLevel } func (u *ConfigUser) UnmarshalJSON(data []byte) error { type rawUser struct { IdString string `json:"id"` EmailString string `json:"email"` + LevelInt int `json:"level"` } var rawUserValue rawUser if err := json.Unmarshal(data, &rawUserValue); err != nil { @@ -27,9 +29,14 @@ func (u *ConfigUser) UnmarshalJSON(data []byte) error { } u.Id = id u.Email = rawUserValue.EmailString + u.LevelValue = config.UserLevel(rawUserValue.LevelInt) return nil } func (u *ConfigUser) ID() *config.ID { return u.Id } + +func (this *ConfigUser) Level() config.UserLevel { + return this.LevelValue +} \ No newline at end of file diff --git a/proxy/vmess/config/user.go b/proxy/vmess/config/user.go index baf52e93..26e55e6f 100644 --- a/proxy/vmess/config/user.go +++ b/proxy/vmess/config/user.go @@ -1,5 +1,27 @@ package config +type UserLevel int + +const ( + UserLevelAdmin = UserLevel(999) + UserLevelUntrusted = UserLevel(0) +) + type User interface { ID() *ID + Level() UserLevel +} + +type UserSettings struct { + PayloadReadTimeout int +} + +func GetUserSettings(level UserLevel) UserSettings { + settings := UserSettings { + PayloadReadTimeout: 120, + } + if level > 0 { + settings.PayloadReadTimeout = 0 + } + return settings } diff --git a/proxy/vmess/protocol/user/userset.go b/proxy/vmess/protocol/user/userset.go index 1ca661d5..707982fd 100644 --- a/proxy/vmess/protocol/user/userset.go +++ b/proxy/vmess/protocol/user/userset.go @@ -15,11 +15,11 @@ const ( type UserSet interface { AddUser(user config.User) error - GetUser(timeHash []byte) (*config.ID, int64, bool) + GetUser(timeHash []byte) (config.User, int64, bool) } type TimedUserSet struct { - validUserIds []*config.ID + validUsers []config.User userHash map[string]indexTimePair userHashDeleteQueue *collect.TimedQueue access sync.RWMutex @@ -32,7 +32,7 @@ type indexTimePair struct { func NewTimedUserSet() UserSet { tus := &TimedUserSet{ - validUserIds: make([]*config.ID, 0, 16), + validUsers: make([]config.User, 0, 16), userHash: make(map[string]indexTimePair, 512), userHashDeleteQueue: collect.NewTimedQueue(updateIntervalSec), access: sync.RWMutex{}, @@ -67,8 +67,8 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) { for now := range tick { nowSec := now.Unix() + cacheDurationSec - for idx, id := range us.validUserIds { - us.generateNewHashes(lastSec, nowSec, idx, id) + for idx, user := range us.validUsers { + us.generateNewHashes(lastSec, nowSec, idx, user.ID()) } lastSec = nowSec } @@ -76,8 +76,8 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) { func (us *TimedUserSet) AddUser(user config.User) error { id := user.ID() - idx := len(us.validUserIds) - us.validUserIds = append(us.validUserIds, id) + idx := len(us.validUsers) + us.validUsers = append(us.validUsers, user) nowSec := time.Now().Unix() lastSec := nowSec - cacheDurationSec @@ -86,12 +86,12 @@ func (us *TimedUserSet) AddUser(user config.User) error { return nil } -func (us TimedUserSet) GetUser(userHash []byte) (*config.ID, int64, bool) { +func (us TimedUserSet) GetUser(userHash []byte) (config.User, int64, bool) { defer us.access.RUnlock() us.access.RLock() pair, found := us.userHash[string(userHash)] if found { - return us.validUserIds[pair.index], pair.timeSec, true + return us.validUsers[pair.index], pair.timeSec, true } return nil, 0, false } diff --git a/proxy/vmess/protocol/vmess.go b/proxy/vmess/protocol/vmess.go index f71a844b..2ac5a269 100644 --- a/proxy/vmess/protocol/vmess.go +++ b/proxy/vmess/protocol/vmess.go @@ -75,12 +75,12 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { return nil, err } - userId, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes]) + userObj, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes]) if !valid { return nil, proxyerrors.InvalidAuthentication } - aesCipher, err := aes.NewCipher(userId.CmdKey()) + aesCipher, err := aes.NewCipher(userObj.ID().CmdKey()) if err != nil { return nil, err } @@ -98,7 +98,7 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) { bufferLen := nBytes request := &VMessRequest{ - UserId: *userId, + UserId: *userObj.ID(), Version: buffer.Value[0], } diff --git a/proxy/vmess/protocol/vmess_test.go b/proxy/vmess/protocol/vmess_test.go index 89e6085d..ec462a63 100644 --- a/proxy/vmess/protocol/vmess_test.go +++ b/proxy/vmess/protocol/vmess_test.go @@ -14,12 +14,17 @@ import ( type TestUser struct { id *config.ID + level config.UserLevel } func (u *TestUser) ID() *config.ID { return u.id } +func (this *TestUser) Level() config.UserLevel { + return this.level +} + func TestVMessSerialization(t *testing.T) { assert := unit.Assert(t) @@ -28,8 +33,10 @@ func TestVMessSerialization(t *testing.T) { t.Fatal(err) } - userSet := mocks.MockUserSet{[]*config.ID{}, make(map[string]int), make(map[string]int64)} - userSet.AddUser(&TestUser{userId}) + userSet := mocks.MockUserSet{[]config.User{}, make(map[string]int), make(map[string]int64)} + userSet.AddUser(&TestUser{ + id: userId, + }) request := new(VMessRequest) request.Version = byte(0x01) @@ -72,8 +79,10 @@ func TestVMessSerialization(t *testing.T) { func BenchmarkVMessRequestWriting(b *testing.B) { userId, _ := config.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51") - userSet := mocks.MockUserSet{[]*config.ID{}, make(map[string]int), make(map[string]int64)} - userSet.AddUser(&TestUser{userId}) + userSet := mocks.MockUserSet{[]config.User{}, make(map[string]int), make(map[string]int64)} + userSet.AddUser(&TestUser{ + id: userId, + }) request := new(VMessRequest) request.Version = byte(0x01) diff --git a/testing/mocks/mockuserset.go b/testing/mocks/mockuserset.go index 23662846..f61cbbde 100644 --- a/testing/mocks/mockuserset.go +++ b/testing/mocks/mockuserset.go @@ -5,20 +5,20 @@ import ( ) type MockUserSet struct { - UserIds []*config.ID + Users []config.User UserHashes map[string]int Timestamps map[string]int64 } func (us *MockUserSet) AddUser(user config.User) error { - us.UserIds = append(us.UserIds, user.ID()) + us.Users = append(us.Users, user) return nil } -func (us *MockUserSet) GetUser(userhash []byte) (*config.ID, int64, bool) { +func (us *MockUserSet) GetUser(userhash []byte) (config.User, int64, bool) { idx, found := us.UserHashes[string(userhash)] if found { - return us.UserIds[idx], us.Timestamps[string(userhash)], true + return us.Users[idx], us.Timestamps[string(userhash)], true } return nil, 0, false }