github.com/cnotch/ipchub@v1.1.0/provider/auth/user.go (about)

     1  // Copyright (c) 2019,CAOHONGJU All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package auth
     6  
     7  import (
     8  	"crypto/md5"
     9  	"encoding/hex"
    10  	"errors"
    11  	"strings"
    12  
    13  	"github.com/cnotch/ipchub/utils/scan"
    14  )
    15  
    16  // AccessRight 访问权限类型
    17  type AccessRight int
    18  
    19  // 权限常量
    20  const (
    21  	PullRight AccessRight = 1 << iota // 拉流权限
    22  	PushRight                         // 推流权限
    23  )
    24  
    25  // UserProvider 用户提供者
    26  type UserProvider interface {
    27  	LoadAll() ([]*User, error)
    28  	Flush(full []*User, saves []*User, removes []*User) error
    29  }
    30  
    31  // User 用户
    32  type User struct {
    33  	Name       string `json:"name"`
    34  	Password   string `json:"password,omitempty"`
    35  	Admin      bool   `json:"admin,omitempty"`
    36  	PushAccess string `json:"push,omitempty"`
    37  	PullAccess string `json:"pull,omitempty"`
    38  
    39  	pushMatchers []PathMatcher
    40  	pullMatchers []PathMatcher
    41  }
    42  
    43  func initMatchers(access string, destMatcher *[]PathMatcher) {
    44  	advance := access
    45  	pathMask := ""
    46  	continueScan := true
    47  	for continueScan {
    48  		advance, pathMask, continueScan = scan.Semicolon.Scan(advance)
    49  		if len(pathMask) == 0 {
    50  			continue
    51  		}
    52  		*destMatcher = append(*destMatcher, NewPathMatcher(pathMask))
    53  	}
    54  }
    55  
    56  func (u *User) init() error {
    57  	u.Name = strings.ToLower(u.Name)
    58  	if u.Admin {
    59  		if len(u.PullAccess) == 0 {
    60  			u.PullAccess = "*"
    61  		}
    62  		if len(u.PushAccess) == 0 {
    63  			u.PushAccess = "*"
    64  		}
    65  	}
    66  
    67  	initMatchers(u.PushAccess, &u.pushMatchers)
    68  	initMatchers(u.PullAccess, &u.pullMatchers)
    69  	return nil
    70  }
    71  
    72  // PasswordMD5 返回口令的MD5字串
    73  func (u *User) PasswordMD5() string {
    74  	if passwordNeedMD5(u.Password) {
    75  		pw := md5.Sum([]byte(u.Password))
    76  		return hex.EncodeToString(pw[:])
    77  	}
    78  	return u.Password
    79  }
    80  
    81  // ValidatePassword 验证密码
    82  func (u *User) ValidatePassword(password string) error {
    83  	if passwordNeedMD5(password) {
    84  		pw := md5.Sum([]byte(password))
    85  		password = hex.EncodeToString(pw[:])
    86  	}
    87  
    88  	if strings.EqualFold(u.PasswordMD5(), password) {
    89  		return nil
    90  	}
    91  	return errors.New("password error")
    92  }
    93  
    94  // ValidatePermission 验证权限
    95  func (u *User) ValidatePermission(path string, right AccessRight) bool {
    96  	var matchers []PathMatcher
    97  	switch right {
    98  	case PushRight:
    99  		matchers = u.pushMatchers
   100  	case PullRight:
   101  		matchers = u.pullMatchers
   102  	}
   103  
   104  	if matchers == nil {
   105  		return false
   106  	}
   107  
   108  	path = strings.TrimSpace(path)
   109  	for _, matcher := range matchers {
   110  		if matcher.Match(path) {
   111  			return true
   112  		}
   113  	}
   114  
   115  	return false
   116  }
   117  
   118  // CopyFrom 从源属性并初始化
   119  func (u *User) CopyFrom(src *User, withPassword bool) {
   120  	if withPassword {
   121  		u.Password = src.Password
   122  	}
   123  	u.Admin = src.Admin
   124  	u.PushAccess = src.PushAccess
   125  	u.PullAccess = src.PullAccess
   126  	u.init()
   127  }
   128  
   129  // 密码是否需要进行md5处理,如果已经是md5则不处理
   130  func passwordNeedMD5(password string) bool {
   131  	if len(password) != 32 {
   132  		return true
   133  	}
   134  
   135  	_, err := hex.DecodeString(password)
   136  	if err != nil {
   137  		return true
   138  	}
   139  
   140  	return false
   141  }