github.com/EagleQL/Xray-core@v1.4.3/proxy/shadowsocks/validator.go (about)

     1  package shadowsocks
     2  
     3  import (
     4  	"crypto/cipher"
     5  	"strings"
     6  	"sync"
     7  
     8  	"github.com/xtls/xray-core/common/protocol"
     9  )
    10  
    11  // Validator stores valid Shadowsocks users.
    12  type Validator struct {
    13  	// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
    14  	email sync.Map
    15  	users sync.Map
    16  }
    17  
    18  // Add a Shadowsocks user, Email must be empty or unique.
    19  func (v *Validator) Add(u *protocol.MemoryUser) error {
    20  	account := u.Account.(*MemoryAccount)
    21  
    22  	if !account.Cipher.IsAEAD() && v.Count() > 0 {
    23  		return newError("The cipher do not support Single-port Multi-user")
    24  	}
    25  
    26  	if u.Email != "" {
    27  		_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
    28  		if loaded {
    29  			return newError("User ", u.Email, " already exists.")
    30  		}
    31  	}
    32  
    33  	v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u)
    34  	return nil
    35  }
    36  
    37  // Del a Shadowsocks user with a non-empty Email.
    38  func (v *Validator) Del(e string) error {
    39  	if e == "" {
    40  		return newError("Email must not be empty.")
    41  	}
    42  	le := strings.ToLower(e)
    43  	u, _ := v.email.Load(le)
    44  	if u == nil {
    45  		return newError("User ", e, " not found.")
    46  	}
    47  	account := u.(*protocol.MemoryUser).Account.(*MemoryAccount)
    48  	v.email.Delete(le)
    49  	v.users.Delete(string(account.Key) + "&" + account.GetCipherName())
    50  	return nil
    51  }
    52  
    53  // Count the number of Shadowsocks users
    54  func (v *Validator) Count() int {
    55  	length := 0
    56  	v.users.Range(func(_, _ interface{}) bool {
    57  		length++
    58  
    59  		return true
    60  	})
    61  	return length
    62  }
    63  
    64  // Get a Shadowsocks user and the user's cipher.
    65  func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) {
    66  	var dataSize int
    67  
    68  	switch command {
    69  	case protocol.RequestCommandTCP:
    70  		dataSize = 16
    71  	case protocol.RequestCommandUDP:
    72  		dataSize = 8192
    73  	}
    74  
    75  	var aeadCipher *AEADCipher
    76  	subkey := make([]byte, 32)
    77  	data := make([]byte, dataSize)
    78  
    79  	v.users.Range(func(key, user interface{}) bool {
    80  		account := user.(*protocol.MemoryUser).Account.(*MemoryAccount)
    81  		aeadCipher = account.Cipher.(*AEADCipher)
    82  		ivLen = aeadCipher.IVSize()
    83  		subkey = subkey[:aeadCipher.KeyBytes]
    84  		hkdfSHA1(account.Key, bs[:ivLen], subkey)
    85  		aead = aeadCipher.AEADAuthCreator(subkey)
    86  
    87  		switch command {
    88  		case protocol.RequestCommandTCP:
    89  			ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
    90  		case protocol.RequestCommandUDP:
    91  			ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
    92  		}
    93  
    94  		if err == nil {
    95  			u = user.(*protocol.MemoryUser)
    96  			return false
    97  		}
    98  		return true
    99  	})
   100  
   101  	return
   102  }
   103  
   104  // Get the only user without authentication
   105  func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) {
   106  	v.users.Range(func(_, user interface{}) bool {
   107  		u = user.(*protocol.MemoryUser)
   108  		return false
   109  	})
   110  	ivLen = u.Account.(*MemoryAccount).Cipher.IVSize()
   111  
   112  	return
   113  }