Skip to content

Commit a4fffed

Browse files
committed
finished app
1 parent 9444d50 commit a4fffed

12 files changed

+72
-4
lines changed

cmd/web/helpers.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"net/http"
77
"runtime/debug"
88
"time"
9+
10+
"github.com/justinas/nosurf"
911
)
1012

1113
// The serverError helper writes an error message and stack trace to the errorLog, // then sends a generic 500 Internal Server Error response to the user.
@@ -34,6 +36,7 @@ func (app *application) addDefaultData(td *templateData, r *http.Request) *templ
3436
td.CurrentYear = time.Now().Year()
3537
td.Flash = app.session.PopString(r, "flash")
3638
td.IsAuthenticated = app.isAuthenticated(r)
39+
td.CSRFToken = nosurf.Token(r)
3740
return td
3841
}
3942

@@ -57,5 +60,9 @@ func (app *application) render(w http.ResponseWriter, r *http.Request, name stri
5760
}
5861

5962
func (app *application) isAuthenticated(r *http.Request) bool {
60-
return app.session.Exists(r, "authenticatedUserID")
63+
isAuthenticated, ok := r.Context().Value(contextKeyIsAuthenticated).(bool)
64+
if !ok {
65+
return false
66+
}
67+
return isAuthenticated
6168
}

cmd/web/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import (
1515
"github.com/morhaham/snippetbox/pkg/models/mysql"
1616
)
1717

18+
type contextKey string
19+
const contextKeyIsAuthenticated = contextKey("isAuthenticated")
20+
1821
type application struct {
1922
errorLog *log.Logger
2023
infoLog *log.Logger

cmd/web/middleware.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package main
22

33
import (
4+
"context"
5+
"errors"
46
"fmt"
57
"net/http"
8+
9+
"github.com/justinas/nosurf"
10+
"github.com/morhaham/snippetbox/pkg/models"
611
)
712

813
func secureHeaders(next http.Handler) http.Handler {
@@ -45,3 +50,37 @@ func (app *application) requireAuthentication(next http.Handler) http.Handler {
4550
next.ServeHTTP(w, r)
4651
})
4752
}
53+
54+
func noSurf(next http.Handler) http.Handler {
55+
csrfHandler := nosurf.New(next)
56+
csrfHandler.SetBaseCookie(http.Cookie{
57+
HttpOnly: true,
58+
Path: "/",
59+
Secure: true,
60+
})
61+
62+
return csrfHandler
63+
}
64+
65+
func (app *application) authenticate(next http.Handler) http.Handler {
66+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
67+
exists := app.session.Exists(r, "authenticateUserID")
68+
if !exists {
69+
next.ServeHTTP(w, r)
70+
return
71+
}
72+
73+
user, err := app.users.Get(app.session.GetInt(r, "authenticateUserID"))
74+
if errors.Is(err, models.ErrorNoRecord) || !user.Active {
75+
app.session.Remove(r, "authenticatedUserID")
76+
next.ServeHTTP(w, r)
77+
return
78+
} else if err != nil {
79+
app.serverError(w, err)
80+
return
81+
}
82+
83+
ctx := context.WithValue(r.Context(), contextKeyIsAuthenticated, true)
84+
next.ServeHTTP(w, r.WithContext(ctx))
85+
})
86+
}

cmd/web/routes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
func (app *application) routes() http.Handler {
1010
standardMiddleware := alice.New(app.recoverPanic, app.logRequest, secureHeaders)
11-
dynamicMiddleware := alice.New(app.session.Enable)
11+
dynamicMiddleware := alice.New(app.session.Enable, noSurf, app.authenticate)
1212

1313
mux := http.NewServeMux()
1414
fileServer := http.FileServer(http.Dir("./ui/static/"))

cmd/web/templates.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type templateData struct {
1616
Form *forms.Form
1717
Flash string
1818
IsAuthenticated bool
19+
CSRFToken string
1920
}
2021

2122
func humanDate(t time.Time) string {

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
require (
1111
filippo.io/edwards25519 v1.1.0 // indirect
1212
github.com/golangcollege/sessions v1.2.0 // indirect
13+
github.com/justinas/nosurf v1.1.1 // indirect
1314
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 // indirect
1415
golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
1516
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ github.com/golangcollege/sessions v1.2.0 h1:2aD9jac/N8NC/y+NEoirYMGlYymzS0ZQN6AS
66
github.com/golangcollege/sessions v1.2.0/go.mod h1:7iTf/FrZku0hWyjV95lES7abH89WBlyBjPyA1htnuks=
77
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
88
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
9+
github.com/justinas/nosurf v1.1.1 h1:92Aw44hjSK4MxJeMSyDa7jwuI9GR2J/JCQiaKvXXSlk=
10+
github.com/justinas/nosurf v1.1.1/go.mod h1:ALpWdSbuNGy2lZWtyXdjkYv4edL23oSEgfBT1gPJ5BQ=
911
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
1012
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 h1:TjszyFsQsyZNHwdVdZ5m7bjmreu0znc2kRYsEml9/Ww=
1113
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

pkg/models/mysql/users.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ func (m *UserModel) Authenticate(email, password string) (int, error) {
6262
return id, nil
6363
}
6464

65-
func (m *UserModel) Get(id int) ([]*models.User, error) {
66-
return nil, nil
65+
func (m *UserModel) Get(id int) (*models.User, error) {
66+
u := &models.User{}
67+
stmt := `SELECT id, name, created, active FROM users WHERE id = ?`
68+
err := m.DB.QueryRow(stmt, id).Scan(&u.ID, &u.Name, &u.Email, &u.Created, &u.Active)
69+
if err != nil {
70+
if errors.Is(err, sql.ErrNoRows) {
71+
return nil, models.ErrorNoRecord
72+
} else {
73+
return nil, err
74+
}
75+
}
76+
77+
return u, nil
6778
}

ui/html/base.layout.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<div>
3232
{{if .IsAuthenticated}}
3333
<form action="/user/logout" method="POST">
34+
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
3435
<button type="submit">Logout</button>
3536
</form>
3637
{{else}}

ui/html/create.page.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{{define "title"}}Create a New Snippet{{end}}
33
{{define "main"}}
44
<form action='/snippet/create' method='POST'>
5+
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
56
{{with .Form}}
67
<div>
78
<label>Title:</label>

ui/html/login.page.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
{{define "main"}}
66
<form action='/user/login' method='POST' novalidate>
7+
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
78
{{with .Form}}
89
{{with .Errors.Get "generic"}}
910
<div class='error'>{{.}}</div>

ui/html/signup.page.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
{{define "main"}}
66
<form action="/user/signup" method="POST" novalidate>
7+
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
78
{{with .Form}}
89
<div>
910
<label>Name:</label>

0 commit comments

Comments
 (0)