Added page protection for unauthorized access

This commit is contained in:
2025-02-14 19:51:40 +11:00
parent 5616b8a248
commit ea4dd2a407
8 changed files with 107 additions and 15 deletions

View File

@@ -18,5 +18,10 @@ tester:
go mod tidy && \
go run . --port 3232 --test --loglevel trace
test:
go mod tidy && \
go test . -v
go test ./middleware -v
clean:
go clean

View File

@@ -12,7 +12,11 @@ func HandleRoot() http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
page.Error("404", "Page not found", "The page or resource you have requested does not exist").Render(r.Context(), w)
page.Error(
"404",
"Page not found",
"The page or resource you have requested does not exist",
).Render(r.Context(), w)
return
}
page.Index().Render(r.Context(), w)

14
handlers/profile.go Normal file
View File

@@ -0,0 +1,14 @@
package handlers
import (
"net/http"
"projectreshoot/view/page"
)
func HandleProfile() http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
page.Profile().Render(r.Context(), w)
},
)
}

View File

@@ -28,6 +28,9 @@ func validateRegistration(conn *sql.DB, r *http.Request) (*db.User, error) {
if formPassword != formConfirmPassword {
return nil, errors.New("Passwords do not match")
}
if len(formPassword) > 72 {
return nil, errors.New("Password exceeds maximum length of 72 bytes")
}
user, err := db.CreateNewUser(conn, formUsername, formPassword)
if err != nil {
return nil, errors.Wrap(err, "db.CreateNewUser")
@@ -47,7 +50,8 @@ func HandleRegisterRequest(
user, err := validateRegistration(conn, r)
if err != nil {
if err.Error() != "Username is taken" &&
err.Error() != "Passwords do not match" {
err.Error() != "Passwords do not match" &&
err.Error() != "Password exceeds maximum length of 72 bytes" {
logger.Warn().Caller().Err(err).Msg("Registration request failed")
w.WriteHeader(http.StatusInternalServerError)
} else {

View File

@@ -0,0 +1,36 @@
package middleware
import (
"net/http"
"projectreshoot/contexts"
"projectreshoot/view/page"
)
// Checks if the user is set in the context and shows 401 page if not logged in
func RequiresLogin(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := contexts.GetUser(r.Context())
if user == nil {
page.Error(
"401",
"Unauthorized",
"Please login to view this page",
).Render(r.Context(), w)
return
}
next.ServeHTTP(w, r)
})
}
// Checks if the user is set in the context and redirects them to profile if
// they are logged in
func RequiresLogout(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user := contexts.GetUser(r.Context())
if user != nil {
http.Redirect(w, r, "/profile", http.StatusFound)
return
}
next.ServeHTTP(w, r)
})
}

View File

@@ -6,6 +6,7 @@ import (
"projectreshoot/config"
"projectreshoot/handlers"
"projectreshoot/middleware"
"projectreshoot/view/page"
"github.com/rs/zerolog"
@@ -31,23 +32,37 @@ func addRoutes(
mux.Handle("GET /about", handlers.HandlePage(page.About()))
// Login page and handlers
mux.Handle("GET /login", handlers.HandleLoginPage(config.TrustedHost))
mux.Handle("POST /login", handlers.HandleLoginRequest(
config,
logger,
conn,
))
mux.Handle("GET /login",
middleware.RequiresLogout(
handlers.HandleLoginPage(config.TrustedHost),
))
mux.Handle("POST /login",
middleware.RequiresLogout(
handlers.HandleLoginRequest(
config,
logger,
conn,
)))
// Register page and handlers
mux.Handle("GET /register", handlers.HandleRegisterPage(config.TrustedHost))
mux.Handle("POST /register", handlers.HandleRegisterRequest(
config,
logger,
conn,
))
mux.Handle("GET /register",
middleware.RequiresLogout(
handlers.HandleRegisterPage(config.TrustedHost),
))
mux.Handle("POST /register",
middleware.RequiresLogout(
handlers.HandleRegisterRequest(
config,
logger,
conn,
)))
// Logout
mux.Handle("POST /logout", handlers.HandleLogout(config, logger, conn))
// Profile page
mux.Handle("GET /profile",
middleware.RequiresLogin(
handlers.HandleProfile(),
))
}

View File

@@ -10,7 +10,8 @@ templ RegisterForm(registerError string) {
errPasswords := "false"
if registerError == "Username is taken" {
errUsername = "true"
} else if registerError == "Passwords do not match" {
} else if registerError == "Passwords do not match" ||
registerError == "Password exceeds maximum length of 72 bytes" {
errPasswords = "true"
}
xdata := fmt.Sprintf(

13
view/page/profile.templ Normal file
View File

@@ -0,0 +1,13 @@
package page
import "projectreshoot/view/layout"
import "projectreshoot/contexts"
templ Profile() {
{{ user := contexts.GetUser(ctx) }}
@layout.Global() {
<div class="">
Hello, { user.Username }
</div>
}
}