diff options
| author | Mitchell Riedstra <mitch@riedstra.dev> | 2022-06-19 23:57:04 -0400 |
|---|---|---|
| committer | Mitchell Riedstra <mitch@riedstra.dev> | 2022-06-19 23:57:04 -0400 |
| commit | bf7d9c79cae53f64fcd04527248987bd4e7ca3c4 (patch) | |
| tree | 0c763f6545cee4a287f5e6fa0a45489a85454325 /cmd/server/middleware.go | |
| parent | 235b8f871fdfa35f9595268d194d28a3de655ec0 (diff) | |
| download | go-website-0.0.17a.tar.gz go-website-0.0.17a.tar.xz | |
0.0.17a / Alpha. Introduce users and page editing.v0.0.17a
Breaking changes:
inc/base.html is now tpl/base.md by default. This can be overridden
on the command line.
404.md is now tpl/404.md. This can be overridden with templatedirectory
in the configuration file.
Additional files:
`auth.json` file that stores credentials and settings for
authorization cookie.
Further notes:
This will likely receive some major updates and changes over
the next few commits. The scaffolidng is now in place for
user accounts, login handling, and page editing.
It's all extremely basic at the moment, on the idea list:
Listing of all markdown files
File uploader and general content management
Flags to turn on/off git integration for edits.
Download / Upload of all markdown files as a backup/restore.
It's of course, all subject to change.
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) + }) +} |
