84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
package api
|
|
|
|
import (
|
|
"errors"
|
|
"runtime"
|
|
|
|
config "github.com/OliveTin/OliveTin/internal/config"
|
|
"github.com/alexedwards/argon2id"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var ErrArgon2Busy = errors.New("too many concurrent password operations")
|
|
|
|
const argon2MaxConcurrent = 10
|
|
|
|
var argon2Sem = make(chan struct{}, argon2MaxConcurrent)
|
|
|
|
var defaultParams = argon2id.Params{
|
|
Memory: 64 * 1024,
|
|
Iterations: 4,
|
|
Parallelism: uint8(runtime.NumCPU()),
|
|
SaltLength: 16,
|
|
KeyLength: 32,
|
|
}
|
|
|
|
func CreateHash(password string) (string, error) {
|
|
select {
|
|
case argon2Sem <- struct{}{}:
|
|
defer func() { <-argon2Sem }()
|
|
default:
|
|
return "", ErrArgon2Busy
|
|
}
|
|
hash, err := argon2id.CreateHash(password, &defaultParams)
|
|
|
|
if err != nil {
|
|
log.Warnf("Error creating hash: %v", err)
|
|
return "", err
|
|
}
|
|
|
|
return hash, nil
|
|
}
|
|
|
|
func createHash(password string) (string, error) {
|
|
return CreateHash(password)
|
|
}
|
|
|
|
func comparePasswordAndHash(password, hash string) (bool, error) {
|
|
select {
|
|
case argon2Sem <- struct{}{}:
|
|
defer func() { <-argon2Sem }()
|
|
default:
|
|
return false, ErrArgon2Busy
|
|
}
|
|
match, err := argon2id.ComparePasswordAndHash(password, hash)
|
|
|
|
if err != nil {
|
|
log.Errorf("Error comparing password and hash: %v", err)
|
|
return false, nil
|
|
}
|
|
|
|
return match, nil
|
|
}
|
|
|
|
func checkUserPassword(cfg *config.Config, username, password string) (bool, error) {
|
|
user := cfg.FindUserByUsername(username)
|
|
if user == nil {
|
|
log.WithFields(log.Fields{"username": username}).Warn("Failed to check password for user, as username was not found")
|
|
return false, nil
|
|
}
|
|
return comparePasswordAndLogResult(password, user.Password, username)
|
|
}
|
|
|
|
func comparePasswordAndLogResult(password, hash, username string) (bool, error) {
|
|
match, err := comparePasswordAndHash(password, hash)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !match {
|
|
log.WithFields(log.Fields{"username": username}).Warn("Password does not match for user")
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|