summaryrefslogtreecommitdiffstats
path: root/internal/auth
diff options
context:
space:
mode:
Diffstat (limited to 'internal/auth')
-rw-r--r--internal/auth/auth.go159
1 files changed, 0 insertions, 159 deletions
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
deleted file mode 100644
index b0de7d9..0000000
--- a/internal/auth/auth.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Package auth manages a htpasswd-compatible password file (bcrypt entries).
-// The file format is one "username:$2a$..." entry per line.
-// nginx auth_basic accepts this file directly via auth_basic_user_file.
-package auth
-
-import (
- "bufio"
- "fmt"
- "os"
- "strings"
- "syscall"
-
- "golang.org/x/crypto/bcrypt"
- "golang.org/x/term"
-)
-
-type Auth struct {
- path string
-}
-
-func New(path string) *Auth { return &Auth{path: path} }
-
-func (a *Auth) AddUser(username string) error {
- users, err := a.read()
- if err != nil && !os.IsNotExist(err) {
- return err
- }
- if _, exists := users[username]; exists {
- return fmt.Errorf("user %q already exists", username)
- }
- pw, err := readPassword("Password: ")
- if err != nil {
- return err
- }
- confirm, err := readPassword("Confirm: ")
- if err != nil {
- return err
- }
- if pw != confirm {
- return fmt.Errorf("passwords do not match")
- }
- hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
- if err != nil {
- return err
- }
- users[username] = string(hash)
- return a.write(users)
-}
-
-func (a *Auth) ChangePassword(username string) error {
- users, err := a.read()
- if err != nil {
- return err
- }
- if _, exists := users[username]; !exists {
- return fmt.Errorf("user %q not found", username)
- }
- pw, err := readPassword("New password: ")
- if err != nil {
- return err
- }
- confirm, err := readPassword("Confirm: ")
- if err != nil {
- return err
- }
- if pw != confirm {
- return fmt.Errorf("passwords do not match")
- }
- hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
- if err != nil {
- return err
- }
- users[username] = string(hash)
- return a.write(users)
-}
-
-func (a *Auth) DeleteUser(username string) error {
- users, err := a.read()
- if err != nil {
- return err
- }
- if _, exists := users[username]; !exists {
- return fmt.Errorf("user %q not found", username)
- }
- delete(users, username)
- return a.write(users)
-}
-
-func (a *Auth) ListUsers() ([]string, error) {
- users, err := a.read()
- if err != nil {
- if os.IsNotExist(err) {
- return nil, nil
- }
- return nil, err
- }
- names := make([]string, 0, len(users))
- for k := range users {
- names = append(names, k)
- }
- return names, nil
-}
-
-func (a *Auth) Verify(username, password string) (bool, error) {
- users, err := a.read()
- if err != nil {
- return false, err
- }
- hash, ok := users[username]
- if !ok {
- return false, nil
- }
- err = bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
- if err == bcrypt.ErrMismatchedHashAndPassword {
- return false, nil
- }
- return err == nil, err
-}
-
-func (a *Auth) read() (map[string]string, error) {
- f, err := os.Open(a.path)
- if err != nil {
- return nil, err
- }
- defer f.Close()
- users := make(map[string]string)
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- line := strings.TrimSpace(scanner.Text())
- if line == "" || strings.HasPrefix(line, "#") {
- continue
- }
- user, hash, ok := strings.Cut(line, ":")
- if ok {
- users[user] = hash
- }
- }
- return users, scanner.Err()
-}
-
-func (a *Auth) write(users map[string]string) error {
- f, err := os.OpenFile(a.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return err
- }
- defer f.Close()
- w := bufio.NewWriter(f)
- for user, hash := range users {
- fmt.Fprintf(w, "%s:%s\n", user, hash)
- }
- return w.Flush()
-}
-
-func readPassword(prompt string) (string, error) {
- fmt.Print(prompt)
- b, err := term.ReadPassword(int(syscall.Stdin))
- fmt.Println()
- return string(b), err
-}