backup/user.go
2024-11-17 15:14:36 +01:00

82 lines
2.0 KiB
Go

package main
import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/scrypt"
)
type User struct {
ID uint64 `json:"id"`
Username string `json:"username"`
Salt string `json:"salt"`
Passwd string `json:"passwd"`
Email string `json:"email"`
}
func NewUser(name, passwd string) (*User, error) {
log.WithFields(log.Fields{"name": name}).Debugf("starting")
defer log.WithFields(log.Fields{"name": name}).Debugf("done")
userID := uint64(0)
for _, v := range cfg.Admin.Users {
userID = max(v.ID+1, userID)
if v.Username == name {
err := errors.New("user already exists")
log.WithFields(log.Fields{"name": name, "error": err}).Errorf("")
return nil, err
}
}
u := &User{
ID: userID,
Username: name,
}
salt := make([]byte, 32)
if _, err := rand.Read(salt); err != nil {
log.WithFields(log.Fields{"name": name, "call": "rand.Read", "error": err}).Errorf("")
return nil, err
}
u.Salt = hex.EncodeToString(salt)
if pass, err := u.HashPassword(passwd); err != nil {
log.WithFields(log.Fields{"name": name, "call": "HashPassword", "error": err}).Errorf("")
return nil, err
} else {
u.Passwd = hex.EncodeToString(pass)
}
return u, nil
}
func (u *User) HashPassword(passwd string) ([]byte, error) {
log.WithFields(log.Fields{}).Debugf("starting")
defer log.WithFields(log.Fields{}).Debugf("done")
//peppering the pass
hash := hmac.New(sha256.New, []byte(cfg.Admin.Secrets.PasswordPepper))
hash.Write([]byte(passwd))
hashPass := hash.Sum(nil)
//salting the hash
salt := make([]byte, 32)
if _, err := hex.Decode(salt, []byte(u.Salt)); err != nil {
log.WithFields(log.Fields{"call": "hex.Decode", "error": err}).Errorf("")
return nil, err
}
if h, err := scrypt.Key(hashPass, salt, cfg.Admin.Secrets.ScryptN, cfg.Admin.Secrets.ScryptR, cfg.Admin.Secrets.ScryptP, 32); err != nil {
log.WithFields(log.Fields{"call": "scrypt.Key", "error": err}).Errorf("")
return h, err
} else {
return h, nil
}
}