2024-10-12 21:45:00 +03:00
|
|
|
package auth
|
2024-10-11 11:38:08 +03:00
|
|
|
|
|
|
|
import (
|
2024-10-13 21:03:44 +03:00
|
|
|
"errors"
|
2024-10-11 23:57:57 +03:00
|
|
|
"log/slog"
|
2024-10-11 11:38:08 +03:00
|
|
|
"net/http"
|
|
|
|
"net/mail"
|
|
|
|
"strings"
|
2024-10-12 21:45:00 +03:00
|
|
|
|
2024-10-13 21:03:44 +03:00
|
|
|
"git.a71.su/Andrew71/pye/internal/storage"
|
2024-10-11 11:38:08 +03:00
|
|
|
)
|
|
|
|
|
2024-10-12 18:39:38 +03:00
|
|
|
func validEmail(email string) bool {
|
2024-10-11 11:38:08 +03:00
|
|
|
_, err := mail.ParseAddress(email)
|
|
|
|
return err == nil
|
|
|
|
}
|
2024-10-12 18:39:38 +03:00
|
|
|
func validPass(pass string) bool {
|
2024-10-12 09:55:58 +03:00
|
|
|
// TODO: Obviously, we *might* want something more sophisticated here
|
2024-10-12 16:59:47 +03:00
|
|
|
return len(pass) >= 8
|
2024-10-11 11:38:08 +03:00
|
|
|
}
|
2024-10-12 18:39:38 +03:00
|
|
|
|
2024-10-13 14:49:41 +03:00
|
|
|
// Register creates a new user with credentials provided through Basic Auth
|
2024-10-13 16:16:19 +03:00
|
|
|
func Register(w http.ResponseWriter, r *http.Request) {
|
2024-10-11 11:38:08 +03:00
|
|
|
email, password, ok := r.BasicAuth()
|
|
|
|
|
2024-10-12 09:55:58 +03:00
|
|
|
if ok {
|
2024-10-11 11:38:08 +03:00
|
|
|
email = strings.TrimSpace(email)
|
|
|
|
password = strings.TrimSpace(password)
|
2024-10-13 21:03:44 +03:00
|
|
|
if !(validEmail(email) && validPass(password)) {
|
2024-10-13 17:18:53 +03:00
|
|
|
slog.Debug("outcome",
|
2024-10-13 17:33:59 +03:00
|
|
|
"valid_email", validEmail(email),
|
|
|
|
"valid_pass", validPass(password),
|
|
|
|
"taken_email", storage.Data.Taken(email))
|
2024-10-12 16:59:47 +03:00
|
|
|
http.Error(w, "invalid auth credentials", http.StatusBadRequest)
|
2024-10-11 23:57:57 +03:00
|
|
|
return
|
2024-10-11 11:38:08 +03:00
|
|
|
}
|
2024-10-13 17:18:53 +03:00
|
|
|
err := storage.Data.Add(email, password)
|
2024-10-11 23:57:57 +03:00
|
|
|
if err != nil {
|
2024-10-13 21:03:44 +03:00
|
|
|
if errors.Is(err, storage.ErrExist) {
|
|
|
|
http.Error(w, "invalid auth credentials", http.StatusBadRequest)
|
|
|
|
} else {
|
|
|
|
http.Error(w, "error adding a new user", http.StatusInternalServerError)
|
|
|
|
}
|
2024-10-12 18:39:38 +03:00
|
|
|
return
|
2024-10-11 23:57:57 +03:00
|
|
|
}
|
2024-10-12 09:55:58 +03:00
|
|
|
w.WriteHeader(http.StatusCreated)
|
2024-10-13 21:03:44 +03:00
|
|
|
w.Write([]byte("user created"))
|
2024-10-12 09:55:58 +03:00
|
|
|
return
|
2024-10-11 11:38:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// No email and password was provided
|
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
|
|
|
|
http.Error(w, "This API requires authorization", http.StatusUnauthorized)
|
|
|
|
}
|
2024-10-11 23:57:57 +03:00
|
|
|
|
2024-10-13 14:49:41 +03:00
|
|
|
// Login returns JWT for a registered user through Basic Auth
|
2024-10-13 16:16:19 +03:00
|
|
|
func Login(w http.ResponseWriter, r *http.Request) {
|
2024-10-11 23:57:57 +03:00
|
|
|
email, password, ok := r.BasicAuth()
|
|
|
|
|
2024-10-12 09:55:58 +03:00
|
|
|
if ok {
|
2024-10-11 23:57:57 +03:00
|
|
|
email = strings.TrimSpace(email)
|
|
|
|
password = strings.TrimSpace(password)
|
2024-10-13 16:16:19 +03:00
|
|
|
user, ok := storage.Data.ByEmail(email)
|
2024-10-13 17:18:53 +03:00
|
|
|
if !ok || !user.Fits(password) {
|
2024-10-12 20:41:30 +03:00
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
|
2024-10-12 16:59:47 +03:00
|
|
|
http.Error(w, "you did something wrong", http.StatusUnauthorized)
|
2024-10-11 23:57:57 +03:00
|
|
|
return
|
|
|
|
}
|
2024-10-12 09:55:58 +03:00
|
|
|
|
2024-10-13 17:18:53 +03:00
|
|
|
token, err := Create(user)
|
2024-10-12 09:55:58 +03:00
|
|
|
if err != nil {
|
|
|
|
http.Error(w, "error creating jwt", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
2024-10-13 17:18:53 +03:00
|
|
|
w.Write([]byte(token))
|
2024-10-12 09:55:58 +03:00
|
|
|
return
|
2024-10-11 23:57:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// No email and password was provided
|
|
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
|
|
|
|
http.Error(w, "This API requires authorization", http.StatusUnauthorized)
|
2024-10-12 09:55:58 +03:00
|
|
|
}
|