aboutsummaryrefslogtreecommitdiff
path: root/cmd/server
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/server')
-rw-r--r--cmd/server/dashboard.go5
-rw-r--r--cmd/server/edit.go14
-rw-r--r--cmd/server/handlers.go23
-rw-r--r--cmd/server/middleware.go114
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)
+ }
}
+*/