2023-07-31 18:11:29 +02:00
|
|
|
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 {
|
2024-11-17 15:14:36 +01:00
|
|
|
ID uint64 `json:"id"`
|
2023-07-31 18:11:29 +02:00
|
|
|
Username string `json:"username"`
|
|
|
|
Salt string `json:"salt"`
|
|
|
|
Passwd string `json:"passwd"`
|
2024-11-17 15:14:36 +01:00
|
|
|
Email string `json:"email"`
|
2023-07-31 18:11:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewUser(name, passwd string) (*User, error) {
|
|
|
|
log.WithFields(log.Fields{"name": name}).Debugf("starting")
|
|
|
|
defer log.WithFields(log.Fields{"name": name}).Debugf("done")
|
|
|
|
|
2024-11-17 15:14:36 +01:00
|
|
|
userID := uint64(0)
|
2023-07-31 18:11:29 +02:00
|
|
|
for _, v := range cfg.Admin.Users {
|
2024-11-17 15:14:36 +01:00
|
|
|
userID = max(v.ID+1, userID)
|
2023-07-31 18:11:29 +02:00
|
|
|
if v.Username == name {
|
|
|
|
err := errors.New("user already exists")
|
|
|
|
log.WithFields(log.Fields{"name": name, "error": err}).Errorf("")
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u := &User{
|
2024-11-17 15:14:36 +01:00
|
|
|
ID: userID,
|
2023-07-31 18:11:29 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|