Browse Source

htpasswd: clean up errors

Signed-off-by: Alejandro Mery <amery@jpi.io>
pull/4/head
Alejandro Mery 1 year ago
parent
commit
02235c36bc
  1. 49
      htpasswd/errors.go
  2. 57
      htpasswd/htpasswd.go

49
htpasswd/errors.go

@ -0,0 +1,49 @@
package htpasswd
import (
"errors"
"strings"
)
var (
// ErrExists indicates the specified user already exists
ErrExists = errors.New("user already exists")
// ErrNotExists indicates the specified user does not exist
ErrNotExists = errors.New("user does not exist")
// ErrInvalidAlgorithm indicates the htpasswd entry doesn't contain a
// valid algorithm signature
ErrInvalidAlgorithm = errors.New("invalid algorithm")
// ErrInvalidPassword indicates the offered password doesn't match
ErrInvalidPassword = errors.New("invalid password")
)
// UserError indicates an error associated to the specified user
type UserError struct {
Name string
Hint string
Err error
}
func (e *UserError) Error() string {
var buf strings.Builder
var reason string
if e.Hint != "" {
reason = e.Hint
} else {
reason = e.Err.Error()
}
if e.Name == "" {
return reason
}
_, _ = buf.WriteString(e.Name)
_, _ = buf.WriteString(": ")
_, _ = buf.WriteString(reason)
return buf.String()
}
func (e *UserError) Unwrap() error {
return e.Err
}

57
htpasswd/htpasswd.go

@ -51,8 +51,10 @@ func Parse(htpasswdBytes []byte) (Passwds, error) {
_, exists := passwords[parts[0]]
if exists {
err = errors.New("invalid htpasswd file - user " +
parts[0] + " defined more than once")
err = &UserError{
Name: parts[0],
Err: ErrExists,
}
return passwords, err
}
passwords[parts[0]] = parts[1]
@ -78,8 +80,12 @@ func CreateUser(file, user, passwd string, algo Hasher) error {
// using the given name, password and hashing algorithm
func (pp Passwds) CreateUser(user, passwd string, algo Hasher) error {
if _, exists := pp[user]; exists {
return fmt.Errorf("user %s already exists", user)
return &UserError{
Name: user,
Err: ErrExists,
}
}
h, err := algo.Hash(passwd)
if err != nil {
return err
@ -106,8 +112,12 @@ func UpdateUser(file, user, passwd string, algo Hasher) error {
// using the given name, password and hashing algorithm
func (pp Passwds) UpdateUser(user, passwd string, algo Hasher) error {
if _, exists := pp[user]; !exists {
return fmt.Errorf("user %s does not exist", user)
return &UserError{
Name: user,
Err: ErrNotExists,
}
}
h, err := algo.Hash(passwd)
if err != nil {
return err
@ -133,7 +143,10 @@ func DeleteUser(file, user string) error {
// DeleteUser deletes the named user from the named file
func (pp Passwds) DeleteUser(user string) error {
if _, exists := pp[user]; !exists {
return fmt.Errorf("user %s does not exist", user)
return &UserError{
Name: user,
Err: ErrNotExists,
}
}
delete(pp, user)
@ -154,12 +167,20 @@ func VerifyUser(file, user, passwd string) error {
// with the given Passwd object
func (pp Passwds) VerifyUser(user, passwd string) error {
if _, ok := pp[user]; !ok {
return fmt.Errorf("user %s does not exist", user)
return &UserError{
Name: user,
Err: ErrNotExists,
}
}
alg, err := identifyHash(pp[user])
if err != nil {
return fmt.Errorf("cannot identify algo %v", alg)
alg := identifyHash(pp[user])
if alg == nil {
return &UserError{
Name: user,
Err: ErrInvalidAlgorithm,
}
}
return alg.Match(passwd, pp[user])
}
@ -177,24 +198,24 @@ func (pp Passwds) Bytes() []byte {
return pass
}
func identifyHash(h string) (Hasher, error) {
func identifyHash(h string) Hasher {
switch {
case strings.HasPrefix(h, "$2a$"), strings.HasPrefix(h, "$2y$"),
strings.HasPrefix(h, "$2x$"), strings.HasPrefix(h, "$2b$"):
return new(Bcrypt), nil
return new(Bcrypt)
case strings.HasPrefix(h, "$apr1$"):
return new(Apr1), nil
return new(Apr1)
case strings.HasPrefix(h, "{SHA}"):
return new(Sha), nil
return new(Sha)
case strings.HasPrefix(h, "{SSHA}"):
return new(Ssha), nil
return new(Ssha)
case strings.HasPrefix(h, "$5$"):
return new(Sha256), nil
return new(Sha256)
case strings.HasPrefix(h, "$6$"):
return new(Sha512), nil
return new(Sha512)
default:
return nil
}
return nil, fmt.Errorf("unsupported hash algorithm")
}
func validLine(parts []string, lineNumber int, line string) (bool, error) {

Loading…
Cancel
Save