all repos — auth-boilerplate @ 9b74357216ccde9dafe9d4d3faa5e8ace72bab5b

A simple Go web-app boilerplate.

make username case-insensitive
Marco Andronaco andronacomarco@gmail.com
Sat, 12 Oct 2024 23:35:14 +0200
commit

9b74357216ccde9dafe9d4d3faa5e8ace72bab5b

parent

d865cd0aaa53991ee5b84ad5f87d22305f3bafc2

2 files changed, 20 insertions(+), 12 deletions(-)

jump to
M src/app/functions.gosrc/app/functions.go

@@ -20,13 +20,16 @@ maxUsernameLength = 10

) var ( - validUsername = regexp.MustCompile(`^[a-z0-9._-]+$`) + validUsername = regexp.MustCompile(`(?i)^[a-z0-9._-]+$`) validEmail = regexp.MustCompile(`^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$`) ) -func sanitizeUsername(username string) (string, error) { - username = strings.ToLower(username) +func getUserByName(username string, excluding uint) (user User, err error) { + err = db.Model(&User{}).Where("upper(username) == upper(?) AND id != ?", username, excluding).First(&user).Error + return +} +func sanitizeUsername(username string) (string, error) { if !validUsername.MatchString(username) || len(username) < minUsernameLength || len(username) > maxUsernameLength { return "", errors.New("invalid username") }

@@ -57,7 +60,7 @@ if err != nil {

http.Error(w, "Could not generate session cookie.", http.StatusInternalServerError) } - ks.Set(cookie.Value, userID, duration) + ks.Set("session:"+cookie.Value, userID, duration) http.SetCookie(w, cookie) }

@@ -103,7 +106,7 @@ cookie, err := r.Cookie("session_token")

if err != nil { return } - return ks.Get(cookie.Value) + return ks.Get("session:" + cookie.Value) } // Middleware to check if the user is logged in
M src/app/handlers.gosrc/app/handlers.go

@@ -50,6 +50,12 @@ http.Error(w, "Invalid email.", http.StatusBadRequest)

return } + _, err = getUserByName(username, 0) + if err == nil { + http.Error(w, "This username is already registered.", http.StatusConflict) + return + } + hashedPassword, salt, err := g.HashPassword(r.FormValue("password")) if err != nil { http.Error(w, "Invalid password.", http.StatusBadRequest)

@@ -65,7 +71,7 @@ }

db.Create(&user) if user.ID == 0 { - http.Error(w, "Username or email already exists.", http.StatusConflict) + http.Error(w, "This email is already registered.", http.StatusConflict) return }

@@ -78,10 +84,9 @@ username := r.FormValue("username")

password := r.FormValue("password") remember := r.FormValue("remember") - var user User - db.Where("username = ?", username).First(&user) + user, err := getUserByName(username, 0) - if user.ID == 0 || !g.CheckPassword(password, user.Salt, user.PasswordHash) { + if err != nil || !g.CheckPassword(password, user.Salt, user.PasswordHash) { http.Error(w, "Invalid credentials", http.StatusUnauthorized) return }

@@ -112,7 +117,7 @@ http.Error(w, "Could not generate reset token.", http.StatusInternalServerError)

return } - ks.Set(resetToken, user.ID, time.Hour) + ks.Set("reset:"+resetToken, user.ID, time.Hour) sendResetEmail(user.Email, resetToken) http.Redirect(w, r, "/login", http.StatusFound)

@@ -121,7 +126,7 @@ }

func getResetPasswordConfirmHandler(w http.ResponseWriter, r *http.Request) { token := r.URL.Query().Get("token") - _, err := ks.Get(token) + _, err := ks.Get("reset:" + token) if err != nil { http.Error(w, "Token is invalid or expired.", http.StatusUnauthorized) return

@@ -132,7 +137,7 @@ }

func postResetPasswordConfirmHandler(w http.ResponseWriter, r *http.Request) { token := r.URL.Query().Get("token") - userID, err := ks.Get(token) + userID, err := ks.Get("reset:" + token) if err != nil { http.Error(w, "Token is invalid or expired.", http.StatusUnauthorized) return