diff --git a/.vscode/settings.json b/.vscode/settings.json index c780c2fd..5996e936 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ // Place your settings in this file to overwrite default and user settings. { + "editor.tabSize": 2, + "go.buildFlags": ["-tags", "json"], "go.lintFlags": ["-tags", "json"], "go.vetFlags": ["-tags", "json"] diff --git a/common/protocol/account.go b/common/protocol/account.go index 00583312..86c7f223 100644 --- a/common/protocol/account.go +++ b/common/protocol/account.go @@ -1,4 +1,20 @@ package protocol +import ( + "github.com/v2ray/v2ray-core/common/dice" +) + type Account interface { } + +type VMessAccount struct { + ID *ID + AlterIDs []*ID +} + +func (this *VMessAccount) AnyValidID() *ID { + if len(this.AlterIDs) == 0 { + return this.ID + } + return this.AlterIDs[dice.Roll(len(this.AlterIDs))] +} diff --git a/common/protocol/account_json.go b/common/protocol/account_json.go new file mode 100644 index 00000000..f17421d7 --- /dev/null +++ b/common/protocol/account_json.go @@ -0,0 +1,36 @@ +// +build json + +package protocol + +import ( + "errors" + + "github.com/v2ray/v2ray-core/common/uuid" +) + +type AccountJson struct { + ID string `json:"id"` + AlterIds uint16 `json:"alterId"` + + Username string `json:"user"` + Password string `json:"pass"` +} + +func (this *AccountJson) GetAccount() (Account, error) { + if len(this.ID) > 0 { + id, err := uuid.ParseString(this.ID) + if err != nil { + return nil, err + } + + primaryID := NewID(id) + alterIDs := NewAlterIDs(primaryID, this.AlterIds) + + return &VMessAccount{ + ID: primaryID, + AlterIDs: alterIDs, + }, nil + } + + return nil, errors.New("Protocol: Malformed account.") +} diff --git a/common/protocol/raw/client.go b/common/protocol/raw/client.go index 77e242c5..d5e89179 100644 --- a/common/protocol/raw/client.go +++ b/common/protocol/raw/client.go @@ -52,7 +52,7 @@ func NewClientSession(idHash protocol.IDHash) *ClientSession { func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) { timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)() - idHash := this.idHash(header.User.AnyValidID().Bytes()) + idHash := this.idHash(header.User.Account.(*protocol.VMessAccount).AnyValidID().Bytes()) idHash.Write(timestamp.Bytes()) writer.Write(idHash.Sum(nil)) @@ -87,7 +87,8 @@ func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, w timestampHash := md5.New() timestampHash.Write(hashTimestamp(timestamp)) iv := timestampHash.Sum(nil) - aesStream := crypto.NewAesEncryptionStream(header.User.ID.CmdKey(), iv) + account := header.User.Account.(*protocol.VMessAccount) + aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv) aesStream.XORKeyStream(buffer.Value, buffer.Value) writer.Write(buffer.Value) diff --git a/common/protocol/raw/encoding_test.go b/common/protocol/raw/encoding_test.go index 7164b7f4..19c7e3e5 100644 --- a/common/protocol/raw/encoding_test.go +++ b/common/protocol/raw/encoding_test.go @@ -15,8 +15,10 @@ func TestRequestSerialization(t *testing.T) { assert := assert.On(t) user := protocol.NewUser( - protocol.NewID(uuid.New()), - nil, + &protocol.VMessAccount{ + ID: protocol.NewID(uuid.New()), + AlterIDs: nil, + }, protocol.UserLevelUntrusted, "test@v2ray.com") diff --git a/common/protocol/raw/server.go b/common/protocol/raw/server.go index 43850d05..78c8ae1b 100644 --- a/common/protocol/raw/server.go +++ b/common/protocol/raw/server.go @@ -60,7 +60,8 @@ func (this *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Requ timestampHash := md5.New() timestampHash.Write(hashTimestamp(timestamp)) iv := timestampHash.Sum(nil) - aesStream := crypto.NewAesDecryptionStream(user.ID.CmdKey(), iv) + account := user.Account.(*protocol.VMessAccount) + aesStream := crypto.NewAesDecryptionStream(account.ID.CmdKey(), iv) decryptor := crypto.NewCryptionReader(aesStream, reader) nBytes, err := io.ReadFull(decryptor, buffer.Value[:41]) diff --git a/common/protocol/user.go b/common/protocol/user.go index 4c765f6c..379b0357 100644 --- a/common/protocol/user.go +++ b/common/protocol/user.go @@ -1,9 +1,5 @@ package protocol -import ( - "github.com/v2ray/v2ray-core/common/dice" -) - type UserLevel byte const ( @@ -12,28 +8,19 @@ const ( ) type User struct { - ID *ID - AlterIDs []*ID - Level UserLevel - Email string + Account Account + Level UserLevel + Email string } -func NewUser(primary *ID, secondary []*ID, level UserLevel, email string) *User { +func NewUser(account Account, level UserLevel, email string) *User { return &User{ - ID: primary, - AlterIDs: secondary, - Level: level, - Email: email, + Account: account, + Level: level, + Email: email, } } -func (this *User) AnyValidID() *ID { - if len(this.AlterIDs) == 0 { - return this.ID - } - return this.AlterIDs[dice.Roll(len(this.AlterIDs))] -} - type UserSettings struct { PayloadReadTimeout int } diff --git a/common/protocol/user_json.go b/common/protocol/user_json.go index 6b1351dd..d171871b 100644 --- a/common/protocol/user_json.go +++ b/common/protocol/user_json.go @@ -2,30 +2,28 @@ package protocol -import ( - "encoding/json" - - "github.com/v2ray/v2ray-core/common/uuid" -) +import "encoding/json" func (u *User) UnmarshalJSON(data []byte) error { type rawUser struct { - IdString string `json:"id"` - EmailString string `json:"email"` - LevelByte byte `json:"level"` - AlterIdCount uint16 `json:"alterId"` + EmailString string `json:"email"` + LevelByte byte `json:"level"` } var rawUserValue rawUser if err := json.Unmarshal(data, &rawUserValue); err != nil { return err } - id, err := uuid.ParseString(rawUserValue.IdString) + + var rawAccount AccountJson + if err := json.Unmarshal(data, &rawAccount); err != nil { + return err + } + account, err := rawAccount.GetAccount() if err != nil { return err } - primaryID := NewID(id) - alterIDs := NewAlterIDs(primaryID, rawUserValue.AlterIdCount) - *u = *NewUser(primaryID, alterIDs, UserLevel(rawUserValue.LevelByte), rawUserValue.EmailString) + + *u = *NewUser(account, UserLevel(rawUserValue.LevelByte), rawUserValue.EmailString) return nil } diff --git a/common/protocol/user_json_test.go b/common/protocol/user_json_test.go index aac35a7c..385900c5 100644 --- a/common/protocol/user_json_test.go +++ b/common/protocol/user_json_test.go @@ -21,8 +21,11 @@ func TestUserParsing(t *testing.T) { "alterId": 100 }`), user) assert.Error(err).IsNil() - assert.String(user.ID.String()).Equals("96edb838-6d68-42ef-a933-25f7ac3a9d09") assert.Byte(byte(user.Level)).Equals(1) + + account, ok := user.Account.(*VMessAccount) + assert.Bool(ok).IsTrue() + assert.String(account.ID.String()).Equals("96edb838-6d68-42ef-a933-25f7ac3a9d09") } func TestInvalidUserJson(t *testing.T) { diff --git a/common/protocol/user_validator.go b/common/protocol/user_validator.go index 00f34f6d..0e3f68e2 100644 --- a/common/protocol/user_validator.go +++ b/common/protocol/user_validator.go @@ -107,18 +107,19 @@ L: func (this *TimedUserValidator) Add(user *User) error { idx := len(this.validUsers) this.validUsers = append(this.validUsers, user) + account := user.Account.(*VMessAccount) nowSec := time.Now().Unix() entry := &idEntry{ - id: user.ID, + id: account.ID, userIdx: idx, lastSec: Timestamp(nowSec - cacheDurationSec), lastSecRemoval: Timestamp(nowSec - cacheDurationSec*3), } this.generateNewHashes(Timestamp(nowSec+cacheDurationSec), idx, entry) this.ids = append(this.ids, entry) - for _, alterid := range user.AlterIDs { + for _, alterid := range account.AlterIDs { entry := &idEntry{ id: alterid, userIdx: idx, diff --git a/proxy/http/client.go b/proxy/http/client.go index d02cfda6..e60d9dd9 100644 --- a/proxy/http/client.go +++ b/proxy/http/client.go @@ -1 +1,4 @@ package http + +type Client struct { +} diff --git a/proxy/http/config.go b/proxy/http/config.go index 0f811ef9..a025358a 100644 --- a/proxy/http/config.go +++ b/proxy/http/config.go @@ -48,3 +48,6 @@ func (this *Config) IsOwnHost(host v2net.Address) bool { } return false } + +type ClientConfig struct { +} diff --git a/proxy/vmess/inbound/command.go b/proxy/vmess/inbound/command.go index b614ff2e..fcadef76 100644 --- a/proxy/vmess/inbound/command.go +++ b/proxy/vmess/inbound/command.go @@ -21,8 +21,8 @@ func (this *VMessInboundHandler) generateCommand(request *protocol.RequestHeader user := inboundHandler.GetUser(request.User.Email) return &protocol.CommandSwitchAccount{ Port: inboundHandler.Port(), - ID: user.ID.UUID(), - AlterIds: uint16(len(user.AlterIDs)), + ID: user.Account.(*protocol.VMessAccount).ID.UUID(), + AlterIds: uint16(len(user.Account.(*protocol.VMessAccount).AlterIDs)), Level: user.Level, ValidMin: byte(availableMin), } diff --git a/proxy/vmess/inbound/inbound.go b/proxy/vmess/inbound/inbound.go index 4b57e646..091b3c0a 100644 --- a/proxy/vmess/inbound/inbound.go +++ b/proxy/vmess/inbound/inbound.go @@ -50,7 +50,11 @@ func (this *userByEmail) Get(email string) (*protocol.User, bool) { if !found { id := protocol.NewID(uuid.New()) alterIDs := protocol.NewAlterIDs(id, this.defaultAlterIDs) - user = protocol.NewUser(id, alterIDs, this.defaultLevel, email) + account := &protocol.VMessAccount{ + ID: id, + AlterIDs: alterIDs, + } + user = protocol.NewUser(account, this.defaultLevel, email) this.cache[email] = user } this.Unlock() diff --git a/proxy/vmess/outbound/command.go b/proxy/vmess/outbound/command.go index 6701c543..9acc67ed 100644 --- a/proxy/vmess/outbound/command.go +++ b/proxy/vmess/outbound/command.go @@ -8,7 +8,11 @@ import ( func (this *VMessOutboundHandler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) { primary := protocol.NewID(cmd.ID) alters := protocol.NewAlterIDs(primary, cmd.AlterIds) - user := protocol.NewUser(primary, alters, cmd.Level, "") + account := &protocol.VMessAccount{ + ID: primary, + AlterIDs: alters, + } + user := protocol.NewUser(account, cmd.Level, "") dest := v2net.TCPDestination(cmd.Host, cmd.Port) this.receiverManager.AddDetour(NewReceiver(dest, user), cmd.ValidMin) } diff --git a/proxy/vmess/outbound/receiver.go b/proxy/vmess/outbound/receiver.go index 59ffac1c..78a960b6 100644 --- a/proxy/vmess/outbound/receiver.go +++ b/proxy/vmess/outbound/receiver.go @@ -25,9 +25,11 @@ func NewReceiver(dest v2net.Destination, users ...*protocol.User) *Receiver { func (this *Receiver) HasUser(user *protocol.User) bool { this.RLock() defer this.RUnlock() + account := user.Account.(*protocol.VMessAccount) for _, u := range this.Accounts { // TODO: handle AlterIds difference. - if u.ID.Equals(user.ID) { + uAccount := u.Account.(*protocol.VMessAccount) + if uAccount.ID.Equals(account.ID) { return true } } diff --git a/proxy/vmess/outbound/receiver_json_test.go b/proxy/vmess/outbound/receiver_json_test.go index b8b08f86..98c5907d 100644 --- a/proxy/vmess/outbound/receiver_json_test.go +++ b/proxy/vmess/outbound/receiver_json_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "testing" + "github.com/v2ray/v2ray-core/common/protocol" . "github.com/v2ray/v2ray-core/proxy/vmess/outbound" "github.com/v2ray/v2ray-core/testing/assert" ) @@ -30,5 +31,7 @@ func TestConfigTargetParsing(t *testing.T) { assert.Error(err).IsNil() assert.Destination(receiver.Destination).EqualsString("tcp:127.0.0.1:80") assert.Int(len(receiver.Accounts)).Equals(1) - assert.String(receiver.Accounts[0].ID.String()).Equals("e641f5ad-9397-41e3-bf1a-e8740dfed019") + + account := receiver.Accounts[0].Account.(*protocol.VMessAccount) + assert.String(account.ID.String()).Equals("e641f5ad-9397-41e3-bf1a-e8740dfed019") } diff --git a/proxy/vmess/outbound/receiver_test.go b/proxy/vmess/outbound/receiver_test.go index dfeb3479..15ccd18e 100644 --- a/proxy/vmess/outbound/receiver_test.go +++ b/proxy/vmess/outbound/receiver_test.go @@ -15,14 +15,22 @@ func TestReceiverUser(t *testing.T) { id := protocol.NewID(uuid.New()) alters := protocol.NewAlterIDs(id, 100) - user := protocol.NewUser(id, alters, protocol.UserLevel(0), "") + account := &protocol.VMessAccount{ + ID: id, + AlterIDs: alters, + } + user := protocol.NewUser(account, protocol.UserLevel(0), "") rec := NewReceiver(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80), user) assert.Bool(rec.HasUser(user)).IsTrue() assert.Int(len(rec.Accounts)).Equals(1) id2 := protocol.NewID(uuid.New()) alters2 := protocol.NewAlterIDs(id2, 100) - user2 := protocol.NewUser(id2, alters2, protocol.UserLevel(0), "") + account2 := &protocol.VMessAccount{ + ID: id2, + AlterIDs: alters2, + } + user2 := protocol.NewUser(account2, protocol.UserLevel(0), "") assert.Bool(rec.HasUser(user2)).IsFalse() rec.AddUser(user2)