From fe1f47a55eb09e4ab7bdb93e120932a1f404f544 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 27 Aug 2024 00:04:22 +0200 Subject: [PATCH] #73 add sign in --- handler.go | 1 + service/auth.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/handler.go b/handler.go index 31f9271..59b5124 100644 --- a/handler.go +++ b/handler.go @@ -24,6 +24,7 @@ func getHandler(db *sql.DB) http.Handler { router.HandleFunc("/auth/signin", service.SignInPage) router.HandleFunc("/auth/signup", service.SignUpPage) router.HandleFunc("/api/auth/signup", service.SignUp(db)) + router.HandleFunc("/api/auth/signin", service.SignIn(db)) router.HandleFunc("/api/auth/userinfo", service.UserInfoComp(db)) return middleware.Logging(middleware.EnableCors(router)) diff --git a/service/auth.go b/service/auth.go index 6670836..ae0783f 100644 --- a/service/auth.go +++ b/service/auth.go @@ -1,6 +1,7 @@ package service import ( + "bytes" "crypto/rand" "database/sql" "encoding/base64" @@ -8,6 +9,7 @@ import ( "net/http" "net/mail" "strings" + "time" "me-fit/template" "me-fit/template/auth" @@ -85,6 +87,53 @@ func SignUp(db *sql.DB) http.HandlerFunc { } } +func SignIn(db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var email = r.FormValue("email") + var password = r.FormValue("password") + + var result bool = true + start := time.Now() + + var user_uuid uuid.UUID + var saved_hash []byte + var salt []byte + err := db.QueryRow("SELECT user_uuid, password, salt FROM user WHERE email = ?", email).Scan(&user_uuid, &saved_hash, &salt) + if err != nil { + result = false + } + + if result { + new_hash := getHashPassword(password, salt) + + if !bytes.Equal(new_hash, saved_hash) { + result = false + } + } + + if result { + result := tryCreateSessionAndSetCookie(r, w, db, user_uuid) + if !result { + return + } + } + + duration := time.Since(start) + time_to_wait := 300 - duration.Milliseconds() + // It is important to sleep for a while to prevent timing attacks + // If the email is correct, the server will calculate the hash, which will take some time + // This way an attacker could guess emails when comparing the response time + // Because of that, we cant use WriteHeader in the middle of the function. We have to wait until the end + time.Sleep(time.Duration(time_to_wait) * time.Millisecond) + + if result { + w.WriteHeader(http.StatusOK) + } else { + http.Error(w, "Unauthorized", http.StatusUnauthorized) + } + } +} + // var ( // metricsAuthSignUp = promauto.NewCounterVec( // prometheus.CounterOpts{