github.com/yaling888/clash@v1.53.0/component/auth/auth.go (about)

     1  package auth
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"sync"
     6  
     7  	"github.com/samber/lo"
     8  )
     9  
    10  type Authenticator interface {
    11  	Verify(user []byte, pass []byte) bool
    12  	HasUser(user []byte) bool
    13  	Users() []string
    14  	RandomUser() *AuthUser
    15  }
    16  
    17  type AuthUser struct {
    18  	User string
    19  	Pass string
    20  }
    21  
    22  var _ Authenticator = (*inMemoryAuthenticator)(nil)
    23  
    24  type inMemoryAuthenticator struct {
    25  	storage   *sync.Map
    26  	usernames []string
    27  }
    28  
    29  func (au *inMemoryAuthenticator) Verify(user []byte, pass []byte) bool {
    30  	realPass, ok := au.storage.Load(string(user))
    31  	return ok && subtle.ConstantTimeCompare(realPass.([]byte), pass) == 1
    32  }
    33  
    34  func (au *inMemoryAuthenticator) HasUser(user []byte) bool {
    35  	_, ok := au.storage.Load(string(user))
    36  	return ok
    37  }
    38  
    39  func (au *inMemoryAuthenticator) Users() []string {
    40  	return au.usernames
    41  }
    42  
    43  func (au *inMemoryAuthenticator) RandomUser() *AuthUser {
    44  	if au == nil || len(au.usernames) == 0 {
    45  		return nil
    46  	}
    47  
    48  	user := lo.Sample(au.usernames)
    49  	realPass, ok := au.storage.Load(user)
    50  	if !ok {
    51  		return nil
    52  	}
    53  
    54  	return &AuthUser{
    55  		User: user,
    56  		Pass: string(realPass.([]byte)),
    57  	}
    58  }
    59  
    60  func NewAuthenticator(users []AuthUser) Authenticator {
    61  	if len(users) == 0 {
    62  		return nil
    63  	}
    64  
    65  	au := &inMemoryAuthenticator{storage: &sync.Map{}}
    66  	usernames := make([]string, 0, len(users))
    67  	for _, user := range users {
    68  		au.storage.Store(user.User, []byte(user.Pass))
    69  		usernames = append(usernames, user.User)
    70  	}
    71  	au.usernames = lo.Uniq(usernames)
    72  
    73  	return au
    74  }