diff --git a/handler.go b/handler.go index 827995b..ae4420b 100644 --- a/handler.go +++ b/handler.go @@ -17,11 +17,13 @@ func getHandler(db *sql.DB) http.Handler { router.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/")))) router.HandleFunc("/app", service.WorkoutPage) - router.HandleFunc("/auth/signin", service.SignInPage) - // router.HandleFunc("/auth/signup", service.SignUpPage) router.HandleFunc("POST /api/workout", service.NewWorkout(db)) router.HandleFunc("GET /api/workout", service.GetWorkouts(db)) router.HandleFunc("DELETE /api/workout", service.DeleteWorkout(db)) + router.HandleFunc("/auth/signin", service.SignInPage) + router.HandleFunc("/auth/signup", service.SignUpPage) + router.HandleFunc("/api/auth/signup", service.SignUp(db)) + return middleware.Logging(middleware.EnableCors(router)) } diff --git a/service/auth.go b/service/auth.go index 6ce3437..db6714a 100644 --- a/service/auth.go +++ b/service/auth.go @@ -1,18 +1,124 @@ package service import ( + "crypto/rand" + "database/sql" + "log" "net/http" + "net/mail" + "strings" "me-fit/template" "me-fit/template/auth" + + "github.com/google/uuid" + "golang.org/x/crypto/argon2" ) func SignInPage(w http.ResponseWriter, r *http.Request) { - signIn := auth.SignIn() + signIn := auth.SignInOrUp(true) template.Layout(signIn).Render(r.Context(), w) } -// func SignUpPage(w http.ResponseWriter, r *http.Request) { -// signIn := auth.SignUp() -// template.Layout(signIn).Render(r.Context(), w) -// } +func SignUpPage(w http.ResponseWriter, r *http.Request) { + signIn := auth.SignInOrUp(false) + template.Layout(signIn).Render(r.Context(), w) +} + +func SignUp(db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + } +} + +// var ( +// metricsAuthSignUp = promauto.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "mefit_api_auth_signup_total", +// Help: "The total number of auth signup api requests processed", +// }, +// []string{"result"}, +// ) +// +// metricsError = promauto.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "mefit_api_error_total", +// Help: "The total number of errors", +// }, +// []string{"result"}, +// ) +// +// // metricsAuthSignIn = promauto.NewCounterVec( +// // prometheus.CounterOpts{ +// // Name: "mefit_api_auth_signin_total", +// // }, +// // []string{"result"}, +// // ) +// +// privateKey = func() *ecdsa.PrivateKey { +// keyBase64 := os.Getenv("PRIVATE_KEY") +// if keyBase64 == "" { +// log.Fatal("PRIVATE_KEY not defined") +// } +// keyData, err := base64.StdEncoding.DecodeString(keyBase64) +// if err != nil { +// log.Fatalf("Could not decode private key: %v", err) +// } +// key, err := x509.ParseECPrivateKey(keyData) +// if err != nil { +// log.Fatalf("Could not parse private key: %v", err) +// } +// log.Println("Successfully imported private key") +// return key +// }() +// ) + +func PostSignup(db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var email = r.FormValue("email") + var password = r.FormValue("password") + + _, err := mail.ParseAddress(email) + if err != nil { + http.Error(w, "Invalid email", http.StatusBadRequest) + return + } + + if len(password) < 8 || + !strings.ContainsAny(password, "0123456789") || + !strings.ContainsAny(password, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") || + !strings.ContainsAny(password, "abcdefghijklmnopqrstuvwxyz") || + !strings.ContainsAny(password, "!@#$%^&*()_+-=[]{}\\|;:'\",.<>/?") { + http.Error(w, "Password needs to be 8 characters long, contain at least one number, one special, one uppercase and one lowercase character", http.StatusBadRequest) + return + } + + user_uuid, err := uuid.NewRandom() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + log.Printf("Could not generate UUID: %v", err) + return + } + + salt := make([]byte, 16) + rand.Read(salt) + + hash := argon2.IDKey([]byte(password), salt, 1, 64*1024, 1, 16) + + _, err = db.Exec("INSERT INTO user (user_uuid, email, email_verified, is_admin, password, salt, created_at) VALUES (?, ?, FALSE, FALSE, ?, ?, datetime())", user_uuid, email, hash, salt) + if err != nil { + if strings.Contains(err.Error(), "email") { + http.Error(w, "Email already exists", http.StatusBadRequest) + return + } + + http.Error(w, err.Error(), http.StatusInternalServerError) + log.Printf("Could not insert user: %v", err) + return + } + + w.WriteHeader(http.StatusOK) + // w.Write([]byte(token)) + } +} diff --git a/template/auth/sign_in.templ b/template/auth/sign_in.templ deleted file mode 100644 index 1ec10e0..0000000 --- a/template/auth/sign_in.templ +++ /dev/null @@ -1,44 +0,0 @@ -package auth - -templ SignIn() { -
-} diff --git a/template/auth/sign_in_or_up.templ b/template/auth/sign_in_or_up.templ new file mode 100644 index 0000000..0ecebce --- /dev/null +++ b/template/auth/sign_in_or_up.templ @@ -0,0 +1,65 @@ +package auth + +templ SignInOrUp(isSignIn bool) { + +} diff --git a/template/layout.templ b/template/layout.templ index 4e5a53e..cf6d97b 100644 --- a/template/layout.templ +++ b/template/layout.templ @@ -10,6 +10,7 @@ templ Layout(comp templ.Component) { +