diff options
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/server/dashboard.go | 5 | ||||
| -rw-r--r-- | cmd/server/edit.go | 14 | ||||
| -rw-r--r-- | cmd/server/handlers.go | 23 | ||||
| -rw-r--r-- | cmd/server/middleware.go | 114 |
4 files changed, 118 insertions, 38 deletions
diff --git a/cmd/server/dashboard.go b/cmd/server/dashboard.go deleted file mode 100644 index a07e722..0000000 --- a/cmd/server/dashboard.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -// func (a *App) DashboardHandler(w http.ResponseWriter, r *http.Request) { -// page.Render(" -// } diff --git a/cmd/server/edit.go b/cmd/server/edit.go index 730e6e9..eb0c4cc 100644 --- a/cmd/server/edit.go +++ b/cmd/server/edit.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "riedstra.dev/mitch/go-website/page" ) @@ -17,6 +18,7 @@ func (a *App) EditPage(w http.ResponseWriter, r *http.Request) { page.Render(w, r, page.TemplateDirectory+"/4xx", map[string]interface{}{ "Title": "Method Not allowed", "Description": "Method not allowed", + "LoggedIn": a.IsLoggedIn(r), }, http.StatusMethodNotAllowed) return @@ -27,12 +29,18 @@ func (a *App) EditPage(w http.ResponseWriter, r *http.Request) { p = filepath.Clean(p) fh, err := os.Open("./" + p + page.Suffix) + if err != nil && strings.Contains(err.Error(), "no such file or directory") { + fh, err = os.Open("./" + page.TemplateDirectory + + "/new-template" + page.Suffix) + } + if err != nil { log.Printf("opening page: %s", err) a.Err500Default(w, r) return } + defer fh.Close() b, err := io.ReadAll(fh) if err != nil { @@ -43,8 +51,9 @@ func (a *App) EditPage(w http.ResponseWriter, r *http.Request) { } page.Render(w, r, page.TemplateDirectory+"/edit", map[string]interface{}{ - "Page": p, - "Content": html.EscapeString(string(b)), + "Page": p, + "Content": html.EscapeString(string(b)), + "LoggedIn": a.IsLoggedIn(r), }, http.StatusOK) } @@ -70,6 +79,7 @@ func (a *App) SaveEditPage(w http.ResponseWriter, r *http.Request) { return } + defer fh.Close() c := bytes.ReplaceAll([]byte(content), []byte{'\r'}, []byte{}) diff --git a/cmd/server/handlers.go b/cmd/server/handlers.go index 1711ae3..c44c19c 100644 --- a/cmd/server/handlers.go +++ b/cmd/server/handlers.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "path/filepath" + "strings" "github.com/gorilla/mux" "riedstra.dev/mitch/go-website/page" @@ -22,7 +23,7 @@ func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) { rtr.PathPrefix("/edit/").Handler( a.RequiresLogin(http.StripPrefix("/edit/", http.HandlerFunc(a.SaveEditPage)))).Methods("POST") - if a.redisPool != nil { + if a.redisPool != nil && !a.IsLoggedIn(r) { rtr.PathPrefix(fmt.Sprintf("/%s/{tag}", a.FeedPrefix)).Handler( rediscache.HandleWithParams(a.redisPool, a.RedisKey, http.HandlerFunc(a.FeedHandler))) @@ -45,9 +46,27 @@ func (a *App) PageHandler(w http.ResponseWriter, r *http.Request) { u = "/index" } + loggedIn := a.IsLoggedIn(r) + + if u == "/dashboard" && loggedIn { + u = page.TemplateDirectory + "/dashboard" + } + + // Render nothing inside of the template directory if we're not logged in + if strings.HasPrefix(u[1:], filepath.Clean(page.TemplateDirectory)) && + !loggedIn { + + page.Render4xx(w, r, map[string]interface{}{ + "LoggedIn": loggedIn, + }, 404) + return + } + u = filepath.Join(".", u) - page.RenderForPath(w, r, u) + page.RenderWithVars(w, r, u, map[string]interface{}{ + "LoggedIn": loggedIn, + }) } func (a *App) RebuildIndexHandler(w http.ResponseWriter, r *http.Request) { diff --git a/cmd/server/middleware.go b/cmd/server/middleware.go index 5e4bf26..0d332cd 100644 --- a/cmd/server/middleware.go +++ b/cmd/server/middleware.go @@ -1,8 +1,10 @@ package main import ( + "errors" "log" "net/http" + "net/url" "time" jwt "github.com/dgrijalva/jwt-go" @@ -30,27 +32,41 @@ func (a *App) LogoutHandler(w http.ResponseWriter, r *http.Request) { SameSite: a.auth.SameSiteStrict, Secure: a.auth.Secure, Value: "logout", - Expires: time.Now().Add(time.Second * 15), //nolint + Expires: time.Now().Add(time.Second), //nolint }) http.Redirect(w, r, "/", http.StatusFound) } func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint - if r.Method == "GET" { + loggedIn := a.IsLoggedIn(r) + + next, _ := url.Parse(r.URL.Query().Get("next")) + + if r.Method == "GET" && !loggedIn { page.RenderForPath(w, r, "login") return } + if r.Method == "GET" && loggedIn { + if next.Path != "" { + http.Redirect(w, r, next.Path, http.StatusFound) + + return + } + + http.Redirect(w, r, "/dashboard", http.StatusFound) + + return + } + if r.Method != "POST" { a.Err500Default(w, r) return } - log.Printf("made it") - username := r.FormValue("username") password := r.FormValue("password") @@ -90,8 +106,6 @@ func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint return } - log.Println(ss) - http.SetCookie(w, &http.Cookie{ Name: "Auth", HttpOnly: a.auth.HTTPOnly, @@ -103,40 +117,82 @@ func (a *App) LoginHandler(w http.ResponseWriter, r *http.Request) { //nolint http.Redirect(w, r, "/login", http.StatusFound) } +func (a *App) IsLoggedIn(r *http.Request) bool { + _, err := a.GetAuthToken(r) + if err != nil { + log.Printf("%s IsLoggedIn: false", r.URL.Path) + return false + } + log.Printf("%s IsLoggedIn: true", r.URL.Path) + return true +} + +func (a *App) GetAuthToken(r *http.Request) (*jwt.Token, error) { + c, err := r.Cookie("Auth") + if err != nil { + return nil, err + } + + token, err := jwt.Parse(c.Value, + func(token *jwt.Token) (interface{}, error) { + return []byte(a.auth.TokenKey), nil + }, + ) + + if err != nil { + return nil, err + } + + if !token.Valid { + return token, errors.New("IsLoggedIn: token not valid") + } + + return token, nil +} + func (a *App) RequiresLogin(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - mustLoginResp := func() { + + if !a.IsLoggedIn(r) { + log.Printf("Unauthorized request %s %s", r.Method, r.URL.Path) 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() + next.ServeHTTP(w, r) - return - } + }) +} - if !token.Valid { - mustLoginResp() +/* +// ConditionalMiddleware is used to select one handler or another based on +// a test function. If the test function returns true, use handler A, otherwise B. +// This allows the test condition to only be run when the handler is selected +// rather than trying to do this as a top level and ending up with a condition +// that is tested on every single request, regardless of whether or not +// the specific handler is selected +type ConditionalMiddleware struct { + A, B http.Handler + Test func(r *http.Request) bool +} - return - } +func NewConditionalMiddleware(test func(r *http.Request) bool, + A, B http.Handler) http.Handler { + return &ConditionalMiddleware{ + Test: test, + A: A, + B: B, + } +} - next.ServeHTTP(w, r) - }) +func (cm *ConditionalMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if cm.Test(r) { + cm.A.ServeHTTP(w, r) + } else { + cm.B.ServeHTTP(w, r) + } } +*/ |
