chore(auth): start refactoring for testable code #181
This commit is contained in:
100
service/auth.go
100
service/auth.go
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"me-fit/db"
|
||||
"me-fit/template"
|
||||
"me-fit/template/auth"
|
||||
tempMail "me-fit/template/mail"
|
||||
@@ -24,6 +25,46 @@ import (
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
type AuthService struct {
|
||||
db db.Auth
|
||||
}
|
||||
|
||||
func NewAuthService(d *sql.DB) *AuthService {
|
||||
return &AuthService{
|
||||
db: db.NewAuthSqlite(d),
|
||||
}
|
||||
}
|
||||
|
||||
func (a AuthService) SignIn(email string, password string) *db.User {
|
||||
|
||||
var result bool = true
|
||||
start := time.Now()
|
||||
|
||||
user, err := a.db.GetUser(email)
|
||||
if err != nil {
|
||||
result = false
|
||||
}
|
||||
|
||||
if result {
|
||||
new_hash := getHashPassword(password, user.Salt)
|
||||
|
||||
if subtle.ConstantTimeCompare(new_hash, user.Password) == 0 {
|
||||
result = false
|
||||
}
|
||||
}
|
||||
|
||||
duration := time.Since(start)
|
||||
timeToWait := 100 - 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
|
||||
// Unfortunatly this makes the code harder to read
|
||||
time.Sleep(time.Duration(timeToWait) * time.Millisecond)
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func HandleSignInPage(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
user := utils.GetUserFromSession(db, r)
|
||||
@@ -245,7 +286,7 @@ func HandleSignUpComp(db *sql.DB) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
result := tryCreateSessionAndSetCookie(r, w, db, userId)
|
||||
result := TryCreateSessionAndSetCookie(r, w, db, userId)
|
||||
if !result {
|
||||
return
|
||||
}
|
||||
@@ -257,61 +298,6 @@ func HandleSignUpComp(db *sql.DB) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func HandleSignInComp(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 (
|
||||
userId uuid.UUID
|
||||
savedHash []byte
|
||||
salt []byte
|
||||
emailVerified bool
|
||||
)
|
||||
err := db.QueryRow("SELECT user_uuid, password, salt, email_verified FROM user WHERE email = ?", email).Scan(&userId, &savedHash, &salt, &emailVerified)
|
||||
if err != nil {
|
||||
result = false
|
||||
}
|
||||
|
||||
if result {
|
||||
new_hash := getHashPassword(password, salt)
|
||||
|
||||
if subtle.ConstantTimeCompare(new_hash, savedHash) == 0 {
|
||||
result = false
|
||||
}
|
||||
}
|
||||
|
||||
if result {
|
||||
result := tryCreateSessionAndSetCookie(r, w, db, userId)
|
||||
if !result {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
duration := time.Since(start)
|
||||
timeToWait := 100 - 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
|
||||
// Unfortunatly this makes the code harder to read
|
||||
time.Sleep(time.Duration(timeToWait) * time.Millisecond)
|
||||
|
||||
if result {
|
||||
if !emailVerified {
|
||||
utils.DoRedirect(w, r, "/auth/verify")
|
||||
} else {
|
||||
utils.DoRedirect(w, r, "/")
|
||||
}
|
||||
} else {
|
||||
auth.Error("Invalid email or password").Render(r.Context(), w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func HandleSignOutComp(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
user := utils.GetUserFromSession(db, r)
|
||||
@@ -617,7 +603,7 @@ func sendVerificationEmail(db *sql.DB, userId string, email string) {
|
||||
utils.SendMail(email, "Welcome to ME-FIT", w.String())
|
||||
}
|
||||
|
||||
func tryCreateSessionAndSetCookie(r *http.Request, w http.ResponseWriter, db *sql.DB, user_uuid uuid.UUID) bool {
|
||||
func TryCreateSessionAndSetCookie(r *http.Request, w http.ResponseWriter, db *sql.DB, user_uuid uuid.UUID) bool {
|
||||
sessionId, err := utils.RandomToken()
|
||||
if err != nil {
|
||||
utils.LogError("Could not generate session ID", err)
|
||||
|
||||
Reference in New Issue
Block a user