diff --git a/.gitignore b/.gitignore index 1faeedb..e578f95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.env tmp/ projectreshoot static/css/output.css diff --git a/cookies/pagefrom.go b/cookies/pagefrom.go new file mode 100644 index 0000000..1e574ee --- /dev/null +++ b/cookies/pagefrom.go @@ -0,0 +1,36 @@ +package cookies + +import ( + "net/http" + "net/url" + "os" + "time" +) + +func CheckPageFrom(w http.ResponseWriter, r *http.Request) string { + pageFromCookie, err := r.Cookie("pagefrom") + if err != nil { + return "/" + } + pageFrom := pageFromCookie.Value + deleteCookie := &http.Cookie{Name: "pagefrom", Value: "", Expires: time.Unix(0, 0)} + http.SetCookie(w, deleteCookie) + return pageFrom +} + +func SetPageFrom(w http.ResponseWriter, r *http.Request) { + referer := r.Referer() + parsedURL, err := url.Parse(referer) + if err != nil { + return + } + var pageFrom string + expectedHost := os.Getenv("TRUSTED_HOST") + if parsedURL.Path == "" || parsedURL.Host != expectedHost { + pageFrom = "/" + } else { + pageFrom = parsedURL.Path + } + pageFromCookie := &http.Cookie{Name: "pagefrom", Value: pageFrom} + http.SetCookie(w, pageFromCookie) +} diff --git a/go.mod b/go.mod index fe89ecb..6ff1fb2 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module projectreshoot go 1.23.5 -require github.com/a-h/templ v0.3.833 +require ( + github.com/a-h/templ v0.3.833 + github.com/joho/godotenv v1.5.1 +) diff --git a/go.sum b/go.sum index bbe292f..dd1c3a7 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,5 @@ github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU= github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/handlers/login.go b/handlers/login.go new file mode 100644 index 0000000..74aed68 --- /dev/null +++ b/handlers/login.go @@ -0,0 +1,75 @@ +package handlers + +import ( + "errors" + "fmt" + "net/http" + "projectreshoot/cookies" + "projectreshoot/view/component/form" + "projectreshoot/view/page" +) + +// TODO: here for testing only, move to database +type User struct { + id int + username string + password string +} + +// TODO: here for testing only, move to database +func testUser() User { + return User{id: 1, username: "Haelnorr", password: "test"} +} + +func validateLogin(r *http.Request) (int, error) { + formUsername := r.FormValue("username") + formPassword := r.FormValue("password") + // TODO: search database for username + validUser := testUser() + // TODO: check password is valid + if formUsername != validUser.username || formPassword != validUser.password { + return 0, errors.New("Username or password incorrect") + } + // TODO: return the users ID + return validUser.id, nil +} + +func checkRememberMe(r *http.Request) bool { + rememberMe := r.FormValue("remember-me") + if rememberMe == "on" { + return true + } else { + return false + } +} + +func HandleLoginRequest() http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + userID, err := validateLogin(r) + if err != nil { + // TODO: add debug log + fmt.Printf("Login failed: %s\n", err) + form.LoginForm(err.Error()).Render(r.Context(), w) + return + } + + // TODO: login success, use the userID to set the session + rememberMe := checkRememberMe(r) + fmt.Printf("Login success, user ID: %v - remember me?: %t\n", userID, rememberMe) + + pageFrom := cookies.CheckPageFrom(w, r) + w.Header().Set("HX-Redirect", pageFrom) + }, + ) +} + +func HandleLoginPage() http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + cookies.SetPageFrom(w, r) + page.Login().Render(r.Context(), w) + }, + ) +} diff --git a/main.go b/main.go index b7d6952..47355af 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "context" "embed" "fmt" + "github.com/joho/godotenv" "io" "net" "net/http" @@ -57,6 +58,10 @@ func run(ctx context.Context, w io.Writer) error { var static embed.FS func main() { + err := godotenv.Load(".env") + if err != nil { + panic(err.Error()) + } ctx := context.Background() if err := run(ctx, os.Stdout); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) diff --git a/server/routes.go b/server/routes.go index f1433e5..9f6e628 100644 --- a/server/routes.go +++ b/server/routes.go @@ -9,8 +9,16 @@ import ( func addRoutes( mux *http.ServeMux, ) { + // Static files mux.Handle("GET /static/", http.StripPrefix("/static/", handlers.HandleStatic())) + + // Index page mux.Handle("GET /", handlers.HandleRoot()) + + // Static pages mux.Handle("GET /about", handlers.HandlePage(page.About())) - mux.Handle("GET /login", handlers.HandlePage(page.Login())) + + // Login page and handlers + mux.Handle("GET /login", handlers.HandleLoginPage()) + mux.Handle("POST /login", handlers.HandleLoginRequest()) } diff --git a/view/component/form/loginform.templ b/view/component/form/loginform.templ index 91cec91..d5bbc88 100644 --- a/view/component/form/loginform.templ +++ b/view/component/form/loginform.templ @@ -5,14 +5,14 @@ import "fmt" templ LoginForm(loginError string) { {{ var errCreds string - if loginError == "Username or password is incorrect" { + if loginError == "Username or password incorrect" { errCreds = "true" } else { errCreds = "false" } xdata := fmt.Sprintf("{credentialError: %s, errorMessage: '%s'}", errCreds, loginError) }} -
+
Forgot password?
diff --git a/view/page/error.templ b/view/page/error.templ index 0ee65ac..f9cc679 100644 --- a/view/page/error.templ +++ b/view/page/error.templ @@ -5,7 +5,7 @@ import "projectreshoot/view/layout" templ Error(code string, err string, message string) { @layout.Global() {
@@ -22,7 +22,7 @@ templ Error(code string, err string, message string) { Go to homepage