|
@@ -0,0 +1,239 @@
|
|
|
+package zTinyPasswd
|
|
|
+
|
|
|
+import (
|
|
|
+ "os"
|
|
|
+ "git.swzry.com/zry/pathutils"
|
|
|
+ "encoding/json"
|
|
|
+ "io/ioutil"
|
|
|
+ "sync"
|
|
|
+ "golang.org/x/crypto/bcrypt"
|
|
|
+ "errors"
|
|
|
+)
|
|
|
+
|
|
|
+type UserData struct {
|
|
|
+ username string `json:"-"`
|
|
|
+ Password string `json:"password"`
|
|
|
+ RoleName string `json:"role"`
|
|
|
+ External string `json:"extdata"`
|
|
|
+}
|
|
|
+
|
|
|
+type UserDatabase struct {
|
|
|
+ UserMap map[string]UserData `json:"user_map"`
|
|
|
+ External map[string]string `json:"external_data"`
|
|
|
+}
|
|
|
+
|
|
|
+type PasswdManager struct{
|
|
|
+ fromFileName bool
|
|
|
+ storage_file *os.File
|
|
|
+ storage UserDatabase
|
|
|
+ stlock sync.RWMutex
|
|
|
+}
|
|
|
+
|
|
|
+func NewPasswdManagerFromFileName(filename string) (*PasswdManager, error) {
|
|
|
+ ex,_ := pathutils.PathExists(filename)
|
|
|
+ var file *os.File
|
|
|
+ var err error
|
|
|
+ if !ex {
|
|
|
+ file,err = os.Create(filename)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ file,err = os.OpenFile(filename, os.O_RDWR, 0666)
|
|
|
+ if err != nil{
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ p, err := NewPasswdManagerFromFileObject(file)
|
|
|
+ if err == nil {
|
|
|
+ p.fromFileName = true
|
|
|
+ }
|
|
|
+ return p, err
|
|
|
+}
|
|
|
+
|
|
|
+func NewPasswdManagerFromFileObject(file *os.File) (*PasswdManager, error) {
|
|
|
+ p := &PasswdManager{
|
|
|
+ storage_file: file,
|
|
|
+ fromFileName: false,
|
|
|
+ }
|
|
|
+ jdata,err := ioutil.ReadAll(p.storage_file)
|
|
|
+ if err != nil{
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ if len(jdata) == 0{
|
|
|
+ p.storage = UserDatabase{
|
|
|
+ UserMap: make(map[string]UserData),
|
|
|
+ External: make(map[string]string),
|
|
|
+ }
|
|
|
+ p.sync()
|
|
|
+ }else {
|
|
|
+ err = json.Unmarshal(jdata, &p.storage)
|
|
|
+ if err != nil {
|
|
|
+ return nil,err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for k,v := range p.storage.UserMap {
|
|
|
+ v.username = k
|
|
|
+ }
|
|
|
+ return p, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) Close() {
|
|
|
+ if this.fromFileName {
|
|
|
+ this.storage_file.Close()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) Add(username string, passwd []byte, role string) error {
|
|
|
+ brpasswd,err := bcrypt.GenerateFromPassword(passwd, 10)
|
|
|
+ if err != nil{
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ passwdinstr := string(brpasswd)
|
|
|
+ this.stlock.Lock()
|
|
|
+ this.storage.UserMap[username] = UserData{
|
|
|
+ username: username,
|
|
|
+ Password: passwdinstr,
|
|
|
+ RoleName: role,
|
|
|
+ External: "",
|
|
|
+ }
|
|
|
+ this.stlock.Unlock()
|
|
|
+ this.sync()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) sync() error {
|
|
|
+ this.stlock.RLock()
|
|
|
+ defer this.stlock.RUnlock()
|
|
|
+ jdata,err := json.MarshalIndent(this.storage, "", "\t")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ this.storage_file.Truncate(0)
|
|
|
+ this.storage_file.Seek(0,0)
|
|
|
+ this.storage_file.Write(jdata)
|
|
|
+ this.storage_file.Sync()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) GetUserInfo(username string) (role string, external string){
|
|
|
+ this.stlock.RLock()
|
|
|
+ defer this.stlock.RUnlock()
|
|
|
+ v, ok := this.storage.UserMap[username]
|
|
|
+ if ok {
|
|
|
+ rs := v.RoleName
|
|
|
+ es := v.External
|
|
|
+ return rs,es
|
|
|
+ }else {
|
|
|
+ return "",""
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) _getUser(username string) *UserData {
|
|
|
+ this.stlock.RLock()
|
|
|
+ defer this.stlock.RUnlock()
|
|
|
+ v, ok := this.storage.UserMap[username]
|
|
|
+ if ok {
|
|
|
+ return &v
|
|
|
+ }else {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) ListUser() []string {
|
|
|
+ this.stlock.RLock()
|
|
|
+ defer this.stlock.RUnlock()
|
|
|
+ ud := make([]string, len(this.storage.UserMap))
|
|
|
+ i := 0
|
|
|
+ for k := range this.storage.UserMap {
|
|
|
+ ud[i] = k
|
|
|
+ i++
|
|
|
+ }
|
|
|
+ return ud
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) Auth(username string, passwd []byte) bool {
|
|
|
+ u := this._getUser(username)
|
|
|
+ if u == nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ this.stlock.RLock()
|
|
|
+ defer this.stlock.RUnlock()
|
|
|
+ err := bcrypt.CompareHashAndPassword([]byte(u.Password), passwd)
|
|
|
+ if err != nil{
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) ChangePassword(username string, newpass []byte) error {
|
|
|
+ brpasswd,err := bcrypt.GenerateFromPassword(newpass, 10)
|
|
|
+ if err != nil{
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ passwdinstr := string(brpasswd)
|
|
|
+ user := this._getUser(username)
|
|
|
+ if user == nil{
|
|
|
+ return errors.New("NoSuchUser")
|
|
|
+ }
|
|
|
+ this.stlock.Lock()
|
|
|
+ user.Password = passwdinstr
|
|
|
+ this.stlock.Unlock()
|
|
|
+ this.sync()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) ChangeExternal(username string, new_external string) error {
|
|
|
+ user := this._getUser(username)
|
|
|
+ if user == nil{
|
|
|
+ return errors.New("NoSuchUser")
|
|
|
+ }
|
|
|
+ this.stlock.Lock()
|
|
|
+ user.External = new_external
|
|
|
+ this.stlock.Unlock()
|
|
|
+ this.sync()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) ChangeRole(username string, new_role string) error {
|
|
|
+ user := this._getUser(username)
|
|
|
+ if user == nil{
|
|
|
+ return errors.New("NoSuchUser")
|
|
|
+ }
|
|
|
+ this.stlock.Lock()
|
|
|
+ user.RoleName = new_role
|
|
|
+ this.stlock.Unlock()
|
|
|
+ this.sync()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) DeleteUser(username string) error {
|
|
|
+ this.stlock.Lock()
|
|
|
+ defer this.stlock.Unlock()
|
|
|
+ _, ok := this.storage.UserMap[username]
|
|
|
+ if ok{
|
|
|
+ delete(this.storage.UserMap, username)
|
|
|
+ return nil
|
|
|
+ }else {
|
|
|
+ return errors.New("NoSuchUser")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (this *PasswdManager) RenameUser(oldname string, new_name string) error {
|
|
|
+ user := this._getUser(oldname)
|
|
|
+ if user == nil{
|
|
|
+ return errors.New("NoSuchUser")
|
|
|
+ }
|
|
|
+ oldn := user.username
|
|
|
+ upwd := user.Password
|
|
|
+ role := user.RoleName
|
|
|
+ uext := user.External
|
|
|
+ this.DeleteUser(oldn)
|
|
|
+ this.Add(new_name, []byte(""), role)
|
|
|
+ this.stlock.Lock()
|
|
|
+ nu := this.storage.UserMap[new_name]
|
|
|
+ nu.Password = upwd
|
|
|
+ nu.External = uext
|
|
|
+ this.stlock.Unlock()
|
|
|
+ return nil
|
|
|
+}
|