This commit is contained in:
lbenedar
2026-03-06 14:58:38 +03:00
parent 94345eff97
commit b6cdb2b860
9 changed files with 24 additions and 1 deletions

View File

@@ -3,6 +3,8 @@ package main
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/justinas/nosurf"
) )
func secureHeaders(next http.Handler) http.Handler { func secureHeaders(next http.Handler) http.Handler {
@@ -49,3 +51,14 @@ func (app *application) requireAuthentication(next http.Handler) http.Handler {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
} }
func noSurf(next http.Handler) http.Handler {
csrfHanlder := nosurf.New(next)
csrfHanlder.SetBaseCookie(http.Cookie{
HttpOnly: true,
Path: "/",
Secure: true,
})
return csrfHanlder
}

View File

@@ -17,7 +17,7 @@ func (app *application) routes() http.Handler {
fileServer := http.FileServer(http.Dir("./ui/static/")) fileServer := http.FileServer(http.Dir("./ui/static/"))
router.Handler(http.MethodGet, "/static/*filepath", http.StripPrefix("/static", fileServer)) router.Handler(http.MethodGet, "/static/*filepath", http.StripPrefix("/static", fileServer))
dynamic := alice.New(app.sessionManager.LoadAndSave) dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf)
router.Handler(http.MethodGet, "/", dynamic.ThenFunc(app.home)) router.Handler(http.MethodGet, "/", dynamic.ThenFunc(app.home))
router.Handler(http.MethodGet, "/snippet/view/:id", dynamic.ThenFunc(app.snippetView)) router.Handler(http.MethodGet, "/snippet/view/:id", dynamic.ThenFunc(app.snippetView))

View File

@@ -7,6 +7,7 @@ import (
"time" "time"
"gitea.local.lab/Lbenedar/snippetbox/internal/models" "gitea.local.lab/Lbenedar/snippetbox/internal/models"
"github.com/justinas/nosurf"
) )
type templateData struct { type templateData struct {
@@ -16,6 +17,7 @@ type templateData struct {
Form any Form any
Flash string Flash string
IsAuthenticated bool IsAuthenticated bool
CSRFToken string
} }
func humanDate(t time.Time) string { func humanDate(t time.Time) string {
@@ -31,6 +33,7 @@ func (app *application) newTemplateData(r *http.Request) *templateData {
CurrentYear: time.Now().Year(), CurrentYear: time.Now().Year(),
Flash: app.sessionManager.PopString(r.Context(), "flash"), Flash: app.sessionManager.PopString(r.Context(), "flash"),
IsAuthenticated: app.isAuthenticated(r), IsAuthenticated: app.isAuthenticated(r),
CSRFToken: nosurf.Token(r),
} }
} }

1
go.mod
View File

@@ -10,5 +10,6 @@ require (
github.com/go-sql-driver/mysql v1.9.3 // indirect github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/justinas/alice v1.2.0 // indirect github.com/justinas/alice v1.2.0 // indirect
github.com/justinas/nosurf v1.2.0 // indirect
golang.org/x/crypto v0.48.0 // indirect golang.org/x/crypto v0.48.0 // indirect
) )

2
go.sum
View File

@@ -13,5 +13,7 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
github.com/justinas/nosurf v1.2.0 h1:yMs1bSRrNiwXk4AS6n8vL2Ssgpb9CB25T/4xrixaK0s=
github.com/justinas/nosurf v1.2.0/go.mod h1:ALpWdSbuNGy2lZWtyXdjkYv4edL23oSEgfBT1gPJ5BQ=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=

View File

@@ -2,6 +2,7 @@
{{define "main"}} {{define "main"}}
<form action='/snippet/create' method='POST'> <form action='/snippet/create' method='POST'>
<input type='hidden' name='csrf_token' value='{{.CSRFToken}}'>
<div> <div>
<label>Title:</label> <label>Title:</label>
{{with .Form.FieldErrors.title}} {{with .Form.FieldErrors.title}}

View File

@@ -2,6 +2,7 @@
{{define "main"}} {{define "main"}}
<form action='/user/login' method='POST' novalidate> <form action='/user/login' method='POST' novalidate>
<input type='hidden' name='csrf_token' value='{{.CSRFToken}}'>
{{range .Form.NonFieldErrors}} {{range .Form.NonFieldErrors}}
<div class='error'>{{.}}</div> <div class='error'>{{.}}</div>
{{end}} {{end}}

View File

@@ -2,6 +2,7 @@
{{define "main"}} {{define "main"}}
<form action='/user/signup' method='POST' novalidate> <form action='/user/signup' method='POST' novalidate>
<input type='hidden' name='csrf_token' value='{{.CSRFToken}}'>
<div> <div>
<label>Name:</label> <label>Name:</label>
{{with .Form.FieldErrors.name}} {{with .Form.FieldErrors.name}}

View File

@@ -9,6 +9,7 @@
<div> <div>
{{if .IsAuthenticated}} {{if .IsAuthenticated}}
<form action='/user/logout' method='POST'> <form action='/user/logout' method='POST'>
<input type='hidden' name='csrf_token' value='{{.CSRFToken}}'>
<button>Logout</button> <button>Logout</button>
</form> </form>
{{else}} {{else}}