mirror of https://github.com/XTLS/Xray-core
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
2.7 KiB
113 lines
2.7 KiB
package shadowsocks |
|
|
|
import ( |
|
"crypto/cipher" |
|
"strings" |
|
"sync" |
|
|
|
"github.com/xtls/xray-core/common/protocol" |
|
) |
|
|
|
// Validator stores valid Shadowsocks users. |
|
type Validator struct { |
|
// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance. |
|
email sync.Map |
|
users sync.Map |
|
} |
|
|
|
// Add a Shadowsocks user, Email must be empty or unique. |
|
func (v *Validator) Add(u *protocol.MemoryUser) error { |
|
account := u.Account.(*MemoryAccount) |
|
|
|
if !account.Cipher.IsAEAD() && v.Count() > 0 { |
|
return newError("The cipher do not support Single-port Multi-user") |
|
} |
|
|
|
if u.Email != "" { |
|
_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u) |
|
if loaded { |
|
return newError("User ", u.Email, " already exists.") |
|
} |
|
} |
|
|
|
v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u) |
|
return nil |
|
} |
|
|
|
// Del a Shadowsocks user with a non-empty Email. |
|
func (v *Validator) Del(e string) error { |
|
if e == "" { |
|
return newError("Email must not be empty.") |
|
} |
|
le := strings.ToLower(e) |
|
u, _ := v.email.Load(le) |
|
if u == nil { |
|
return newError("User ", e, " not found.") |
|
} |
|
account := u.(*protocol.MemoryUser).Account.(*MemoryAccount) |
|
v.email.Delete(le) |
|
v.users.Delete(string(account.Key) + "&" + account.GetCipherName()) |
|
return nil |
|
} |
|
|
|
// Count the number of Shadowsocks users |
|
func (v *Validator) Count() int { |
|
length := 0 |
|
v.users.Range(func(_, _ interface{}) bool { |
|
length++ |
|
|
|
return true |
|
}) |
|
return length |
|
} |
|
|
|
// Get a Shadowsocks user and the user's cipher. |
|
func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) { |
|
var dataSize int |
|
|
|
switch command { |
|
case protocol.RequestCommandTCP: |
|
dataSize = 16 |
|
case protocol.RequestCommandUDP: |
|
dataSize = 8192 |
|
} |
|
|
|
var aeadCipher *AEADCipher |
|
subkey := make([]byte, 32) |
|
data := make([]byte, dataSize) |
|
|
|
v.users.Range(func(key, user interface{}) bool { |
|
account := user.(*protocol.MemoryUser).Account.(*MemoryAccount) |
|
aeadCipher = account.Cipher.(*AEADCipher) |
|
ivLen = aeadCipher.IVSize() |
|
subkey = subkey[:aeadCipher.KeyBytes] |
|
hkdfSHA1(account.Key, bs[:ivLen], subkey) |
|
aead = aeadCipher.AEADAuthCreator(subkey) |
|
|
|
switch command { |
|
case protocol.RequestCommandTCP: |
|
ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil) |
|
case protocol.RequestCommandUDP: |
|
ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil) |
|
} |
|
|
|
if err == nil { |
|
u = user.(*protocol.MemoryUser) |
|
return false |
|
} |
|
return true |
|
}) |
|
|
|
return |
|
} |
|
|
|
// Get the only user without authentication |
|
func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) { |
|
v.users.Range(func(_, user interface{}) bool { |
|
u = user.(*protocol.MemoryUser) |
|
return false |
|
}) |
|
ivLen = u.Account.(*MemoryAccount).Cipher.IVSize() |
|
|
|
return |
|
}
|
|
|