local_user_login.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package api
  2. import (
  3. "errors"
  4. "runtime"
  5. config "github.com/OliveTin/OliveTin/internal/config"
  6. "github.com/alexedwards/argon2id"
  7. log "github.com/sirupsen/logrus"
  8. )
  9. var ErrArgon2Busy = errors.New("too many concurrent password operations")
  10. const argon2MaxConcurrent = 10
  11. var argon2Sem = make(chan struct{}, argon2MaxConcurrent)
  12. var defaultParams = argon2id.Params{
  13. Memory: 64 * 1024,
  14. Iterations: 4,
  15. Parallelism: uint8(runtime.NumCPU()),
  16. SaltLength: 16,
  17. KeyLength: 32,
  18. }
  19. func CreateHash(password string) (string, error) {
  20. select {
  21. case argon2Sem <- struct{}{}:
  22. defer func() { <-argon2Sem }()
  23. default:
  24. return "", ErrArgon2Busy
  25. }
  26. hash, err := argon2id.CreateHash(password, &defaultParams)
  27. if err != nil {
  28. log.Warnf("Error creating hash: %v", err)
  29. return "", err
  30. }
  31. return hash, nil
  32. }
  33. func createHash(password string) (string, error) {
  34. return CreateHash(password)
  35. }
  36. func comparePasswordAndHash(password, hash string) (bool, error) {
  37. select {
  38. case argon2Sem <- struct{}{}:
  39. defer func() { <-argon2Sem }()
  40. default:
  41. return false, ErrArgon2Busy
  42. }
  43. match, err := argon2id.ComparePasswordAndHash(password, hash)
  44. if err != nil {
  45. log.Errorf("Error comparing password and hash: %v", err)
  46. return false, nil
  47. }
  48. return match, nil
  49. }
  50. func isLocalInteractiveLoginDisabledForUser(cfg *config.Config, username string) bool {
  51. user := cfg.FindUserByUsername(username)
  52. if user == nil {
  53. return false
  54. }
  55. return user.Password == ""
  56. }
  57. func checkUserPassword(cfg *config.Config, username, password string) (bool, error) {
  58. user := cfg.FindUserByUsername(username)
  59. if user == nil {
  60. log.WithFields(log.Fields{"username": username}).Warn("Failed to check password for user, as username was not found")
  61. return false, nil
  62. }
  63. return comparePasswordAndLogResult(password, user.Password, username)
  64. }
  65. func comparePasswordAndLogResult(password, hash, username string) (bool, error) {
  66. match, err := comparePasswordAndHash(password, hash)
  67. if err != nil {
  68. return false, err
  69. }
  70. if !match {
  71. log.WithFields(log.Fields{"username": username}).Warn("Password does not match for user")
  72. return false, nil
  73. }
  74. return true, nil
  75. }