diff options
Diffstat (limited to 'cmd/server/middleware.go')
| -rw-r--r-- | cmd/server/middleware.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/cmd/server/middleware.go b/cmd/server/middleware.go new file mode 100644 index 0000000..5e4bf26 --- /dev/null +++ b/cmd/server/middleware.go @@ -0,0 +1,142 @@ +package main + +import ( + "log" + "net/http" + "time" + + jwt "github.com/dgrijalva/jwt-go" + "riedstra.dev/mitch/go-website/page" + "riedstra.dev/mitch/go-website/users" +) + +func (a *App) Err5xx(w http.ResponseWriter, r *http.Request, + statusCode int, title, desc string) { + page.Render5xx(w, r, map[string]interface{}{ + "Error": title, + "Description": desc, + }, statusCode) +} + +func (a *App) Err500Default(w http.ResponseWriter, r *http.Request) { + a.Err5xx(w, r, http.StatusInternalServerError, "Internal server error", + "Internal server error.") +} + +func (a *App) LogoutHandler(w http.ResponseWriter, r *http.Request) { + http.SetCookie(w, &http.Cookie{ + Name: "Auth", + HttpOnly: a.auth.HTTPOnly, + SameSite: a.auth.SameSiteStrict, + Secure: a.auth.Secure, + Value: "logout", + Expires: time.Now().Add(time.Second * 15), //nolint + }) + + http.Redirect(w, r, "/", http.StatusFound) +} + +func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint + if r.Method == "GET" { + page.RenderForPath(w, r, "login") + + return + } + + if r.Method != "POST" { + a.Err500Default(w, r) + + return + } + + log.Printf("made it") + + username := r.FormValue("username") + password := r.FormValue("password") + + var ( + err error = nil + u *users.SiteUser + found = false + ) + + for _, u = range a.auth.Users { + if u.Username == username { + err = u.CheckPassword(password) + found = true + } + } + + if err != nil || !found { + page.Render(w, r, "login", map[string]interface{}{ + "Error": "Invalid username or password", + "Username": username, + }, http.StatusUnauthorized) + + return + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS512, &jwt.StandardClaims{ + ExpiresAt: time.Now().Add( + time.Hour * time.Duration(a.auth.LoginHours)).Unix(), + Id: u.Username, + }) + + ss, err := token.SignedString([]byte(a.auth.TokenKey)) + if err != nil { + log.Println("login: encountered while setting up JWT: ", err) + a.Err500Default(w, r) + + return + } + + log.Println(ss) + + http.SetCookie(w, &http.Cookie{ + Name: "Auth", + HttpOnly: a.auth.HTTPOnly, + SameSite: a.auth.SameSiteStrict, + Secure: a.auth.Secure, + Value: ss, + }) + + http.Redirect(w, r, "/login", http.StatusFound) +} + +func (a *App) RequiresLogin(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mustLoginResp := func() { + page.Render(w, r, "login", map[string]interface{}{ + "Error": "You must login to view this page", + }, http.StatusUnauthorized) + } + + c, err := r.Cookie("Auth") + if err != nil { + mustLoginResp() + + return + } + + token, err := jwt.Parse(c.Value, + func(token *jwt.Token) (interface{}, error) { + return []byte(a.auth.TokenKey), nil + }, + ) + + if err != nil { + log.Printf("Unauthorized request %s %s", r.Method, r.URL.Path) + mustLoginResp() + + return + } + + if !token.Valid { + mustLoginResp() + + return + } + + next.ServeHTTP(w, r) + }) +} |
