1 Commits 0503a079bf ... 7acc51e9dd

Author SHA1 Message Date
  zry 7acc51e9dd Coomit 2018-08-08 02:08. 5 years ago
1 changed files with 239 additions and 0 deletions
  1. 239 0
      zTinyPasswd.go

+ 239 - 0
zTinyPasswd.go

@@ -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
+}