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 {
	Username string `json:"username"`
	Salt     string `json:"salt"`
	Passwd   string `json:"passwd"`
}

func NewUser(name, passwd string) (*User, error) {
	log.WithFields(log.Fields{"name": name}).Debugf("starting")
	defer log.WithFields(log.Fields{"name": name}).Debugf("done")

	for _, v := range cfg.Admin.Users {
		if v.Username == name {
			err := errors.New("user already exists")
			log.WithFields(log.Fields{"name": name, "error": err}).Errorf("")
			return nil, err
		}
	}

	u := &User{
		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
	}

}
