diff --git a/cmd/lavender/serve.go b/cmd/lavender/serve.go index f32367f..6a34a99 100644 --- a/cmd/lavender/serve.go +++ b/cmd/lavender/serve.go @@ -8,9 +8,9 @@ import ( "github.com/1f349/lavender/conf" "github.com/1f349/lavender/database" "github.com/1f349/lavender/logger" - "github.com/1f349/lavender/pages" "github.com/1f349/lavender/role" "github.com/1f349/lavender/server" + "github.com/1f349/lavender/web" "github.com/1f349/mjwt" "github.com/charmbracelet/log" "github.com/cloudflare/tableflip" @@ -121,7 +121,7 @@ func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) logger.Logger.Fatal("Failed to add initial user", "err", err) } - if err := pages.LoadPages(wd); err != nil { + if err := web.LoadPages(wd); err != nil { logger.Logger.Fatal("Failed to load page templates:", err) } diff --git a/server/edit.go b/server/edit.go index 30ea342..bbd0abe 100644 --- a/server/edit.go +++ b/server/edit.go @@ -5,7 +5,7 @@ import ( auth2 "github.com/1f349/lavender/auth" "github.com/1f349/lavender/database" "github.com/1f349/lavender/lists" - "github.com/1f349/lavender/pages" + "github.com/1f349/lavender/web" "github.com/google/uuid" "github.com/julienschmidt/httprouter" "net/http" @@ -35,7 +35,7 @@ func (h *httpServer) EditGet(rw http.ResponseWriter, req *http.Request, _ httpro Secure: true, SameSite: http.SameSiteLaxMode, }) - pages.RenderPageTemplate(rw, "edit", map[string]any{ + web.RenderPageTemplate(rw, "edit", map[string]any{ "ServiceName": h.conf.ServiceName, "User": user, "Nonce": lNonce, diff --git a/server/home.go b/server/home.go index b3edfce..c6f730f 100644 --- a/server/home.go +++ b/server/home.go @@ -3,8 +3,8 @@ package server import ( auth2 "github.com/1f349/lavender/auth" "github.com/1f349/lavender/database" - "github.com/1f349/lavender/pages" "github.com/1f349/lavender/role" + "github.com/1f349/lavender/web" "github.com/google/uuid" "github.com/julienschmidt/httprouter" "net/http" @@ -24,7 +24,7 @@ func (h *httpServer) Home(rw http.ResponseWriter, req *http.Request, _ httproute }) if auth.IsGuest() { - pages.RenderPageTemplate(rw, "index-guest", map[string]any{ + web.RenderPageTemplate(rw, "index-guest", map[string]any{ "ServiceName": h.conf.ServiceName, }) return @@ -37,7 +37,7 @@ func (h *httpServer) Home(rw http.ResponseWriter, req *http.Request, _ httproute return nil }) - pages.RenderPageTemplate(rw, "index", map[string]any{ + web.RenderPageTemplate(rw, "index", map[string]any{ "ServiceName": h.conf.ServiceName, "Auth": auth, "Nonce": lNonce, diff --git a/server/login.go b/server/login.go index 6e64719..e64db9c 100644 --- a/server/login.go +++ b/server/login.go @@ -10,7 +10,7 @@ import ( "github.com/1f349/lavender/database" "github.com/1f349/lavender/database/types" "github.com/1f349/lavender/issuer" - "github.com/1f349/lavender/pages" + "github.com/1f349/lavender/web" "github.com/1f349/mjwt" "github.com/1f349/mjwt/auth" "github.com/golang-jwt/jwt/v4" @@ -78,7 +78,7 @@ func (h *httpServer) loginGet(rw http.ResponseWriter, req *http.Request, _ httpr fmt.Printf("%#v\n", h.testAuthSources(req, userPtr, auth2.FactorFirst)) - pages.RenderPageTemplate(rw, "login-memory", map[string]any{ + web.RenderPageTemplate(rw, "login-memory", map[string]any{ "ServiceName": h.conf.ServiceName, "LoginName": cookie.Value, "Redirect": req.URL.Query().Get("redirect"), @@ -89,7 +89,7 @@ func (h *httpServer) loginGet(rw http.ResponseWriter, req *http.Request, _ httpr } // render different page sources - pages.RenderPageTemplate(rw, "login", map[string]any{ + web.RenderPageTemplate(rw, "login", map[string]any{ "ServiceName": h.conf.ServiceName, "LoginName": "", "Redirect": req.URL.Query().Get("redirect"), diff --git a/server/mail.go b/server/mail.go index 55759f7..79f4b16 100644 --- a/server/mail.go +++ b/server/mail.go @@ -2,7 +2,7 @@ package server import ( "github.com/1f349/lavender/database" - "github.com/1f349/lavender/pages" + "github.com/1f349/lavender/web" "github.com/emersion/go-message/mail" "github.com/julienschmidt/httprouter" "net/http" @@ -39,7 +39,7 @@ func (h *httpServer) MailPassword(rw http.ResponseWriter, _ *http.Request, param return } - pages.RenderPageTemplate(rw, "reset-password", map[string]any{ + web.RenderPageTemplate(rw, "reset-password", map[string]any{ "ServiceName": h.conf.ServiceName, "Code": code, }) diff --git a/server/manage-apps.go b/server/manage-apps.go index a246a40..558304c 100644 --- a/server/manage-apps.go +++ b/server/manage-apps.go @@ -3,9 +3,9 @@ package server import ( auth2 "github.com/1f349/lavender/auth" "github.com/1f349/lavender/database" - "github.com/1f349/lavender/pages" "github.com/1f349/lavender/password" "github.com/1f349/lavender/role" + "github.com/1f349/lavender/web" "github.com/google/uuid" "github.com/julienschmidt/httprouter" "net/http" @@ -54,7 +54,7 @@ func (h *httpServer) ManageAppsGet(rw http.ResponseWriter, req *http.Request, _ m["EditApp"] = i rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusOK) - pages.RenderPageTemplate(rw, "manage-apps-edit", m) + web.RenderPageTemplate(rw, "manage-apps-edit", m) return } } @@ -64,7 +64,7 @@ func (h *httpServer) ManageAppsGet(rw http.ResponseWriter, req *http.Request, _ rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusOK) - pages.RenderPageTemplate(rw, "manage-apps", m) + web.RenderPageTemplate(rw, "manage-apps", m) } func (h *httpServer) ManageAppsCreateGet(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, auth auth2.UserAuth) { @@ -83,7 +83,7 @@ func (h *httpServer) ManageAppsCreateGet(rw http.ResponseWriter, req *http.Reque rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusOK) - pages.RenderPageTemplate(rw, "manage-apps-create", m) + web.RenderPageTemplate(rw, "manage-apps-create", m) } func (h *httpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, auth auth2.UserAuth) { diff --git a/server/manage-users.go b/server/manage-users.go index 7d243e9..bbaa2a2 100644 --- a/server/manage-users.go +++ b/server/manage-users.go @@ -3,8 +3,8 @@ package server import ( auth2 "github.com/1f349/lavender/auth" "github.com/1f349/lavender/database" - "github.com/1f349/lavender/pages" "github.com/1f349/lavender/role" + "github.com/1f349/lavender/web" "github.com/julienschmidt/httprouter" "golang.org/x/sync/errgroup" "net/http" @@ -51,7 +51,7 @@ func (h *httpServer) ManageUsersGet(rw http.ResponseWriter, req *http.Request, _ m["EditUser"] = i rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusOK) - pages.RenderPageTemplate(rw, "manage-users-edit", m) + web.RenderPageTemplate(rw, "manage-users-edit", m) return } } @@ -61,7 +61,7 @@ func (h *httpServer) ManageUsersGet(rw http.ResponseWriter, req *http.Request, _ rw.Header().Set("Content-Type", "text/html") rw.WriteHeader(http.StatusOK) - pages.RenderPageTemplate(rw, "manage-users", m) + web.RenderPageTemplate(rw, "manage-users", m) } func (h *httpServer) ManageUsersPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params, auth auth2.UserAuth) { diff --git a/server/oauth.go b/server/oauth.go index 445fa41..1046b59 100644 --- a/server/oauth.go +++ b/server/oauth.go @@ -7,9 +7,9 @@ import ( clientStore "github.com/1f349/lavender/client-store" "github.com/1f349/lavender/database" "github.com/1f349/lavender/logger" - "github.com/1f349/lavender/pages" "github.com/1f349/lavender/scope" "github.com/1f349/lavender/utils" + "github.com/1f349/lavender/web" "github.com/1f349/mjwt" "github.com/go-oauth2/oauth2/v4" "github.com/go-oauth2/oauth2/v4/errors" @@ -232,7 +232,7 @@ func (h *httpServer) authorizeEndpoint(rw http.ResponseWriter, req *http.Request } rw.WriteHeader(http.StatusOK) - pages.RenderPageTemplate(rw, "oauth-authorize", map[string]any{ + web.RenderPageTemplate(rw, "oauth-authorize", map[string]any{ "ServiceName": h.conf.ServiceName, "AppName": appName, "AppDomain": appDomain, diff --git a/server/otp.go b/server/otp.go index cd38e7e..25171fb 100644 --- a/server/otp.go +++ b/server/otp.go @@ -5,7 +5,7 @@ import ( "encoding/base64" auth2 "github.com/1f349/lavender/auth" "github.com/1f349/lavender/database" - "github.com/1f349/lavender/pages" + "github.com/1f349/lavender/web" "github.com/julienschmidt/httprouter" "github.com/skip2/go-qrcode" "github.com/xlzd/gotp" @@ -19,7 +19,7 @@ func (h *httpServer) editOtpPost(rw http.ResponseWriter, req *http.Request, _ ht if req.Method == http.MethodPost && req.FormValue("remove") == "1" { if !req.Form.Has("code") { // render page - pages.RenderPageTemplate(rw, "remove-otp", map[string]any{ + web.RenderPageTemplate(rw, "remove-otp", map[string]any{ "ServiceName": h.conf.ServiceName, }) return @@ -95,7 +95,7 @@ func (h *httpServer) editOtpPost(rw http.ResponseWriter, req *http.Request, _ ht } // render page - pages.RenderPageTemplate(rw, "edit-otp", map[string]any{ + web.RenderPageTemplate(rw, "edit-otp", map[string]any{ "ServiceName": h.conf.ServiceName, "OtpQr": template.URL("data:qrImg/png;base64," + base64.StdEncoding.EncodeToString(qrBuf.Bytes())), "QrWidth": qrWidth, diff --git a/server/server.go b/server/server.go index a1cfa82..9a993da 100644 --- a/server/server.go +++ b/server/server.go @@ -8,16 +8,14 @@ import ( "github.com/1f349/lavender/database" "github.com/1f349/lavender/issuer" "github.com/1f349/lavender/logger" - "github.com/1f349/lavender/pages" + "github.com/1f349/lavender/web" "github.com/1f349/mjwt" "github.com/go-oauth2/oauth2/v4/manage" "github.com/go-oauth2/oauth2/v4/server" "github.com/julienschmidt/httprouter" "net/http" "net/url" - "path" "strings" - "time" ) var errInvalidScope = errors.New("missing required scope") @@ -58,8 +56,6 @@ func SetupRouter(r *httprouter.Router, config conf.Conf, db *database.Queries, s // remove last slash from baseUrl config.BaseUrl = strings.TrimRight(config.BaseUrl, "/") - contentCache := time.Now() - authBasic := &auth.BasicLogin{DB: db} authOtp := &auth.OtpLogin{DB: db} authOAuth := &auth.OAuthLogin{DB: db, BaseUrl: config.BaseUrl} @@ -101,8 +97,7 @@ func SetupRouter(r *httprouter.Router, config conf.Conf, db *database.Queries, s http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) return } - out := pages.RenderCss(path.Join("assets", name)) - http.ServeContent(rw, req, path.Base(name), contentCache, out) + web.RenderWebAsset(rw, req, name) }) // login steps diff --git a/web/web.go b/web/web.go index 3cf8094..cc79f32 100644 --- a/web/web.go +++ b/web/web.go @@ -58,13 +58,15 @@ func RenderPageTemplate(wr io.Writer, name string, data any) { } } -func RenderWebAsset(rw http.ResponseWriter, req *http.Request) { - name := req.URL.Path - +func RenderWebAsset(rw http.ResponseWriter, req *http.Request, name string) { // Disallow paths containing ".." - directory traversal is a security issue. + if containsDotDot(name) { + http.Error(rw, "400 Bad Request", http.StatusBadRequest) + } + // Disallow paths ending in ".html" - these should only be processed by HTML // template. - if containsDotDot(name) || strings.HasSuffix(name, ".html") { + if strings.HasSuffix(name, ".html") { http.Error(rw, "404 Not Found", http.StatusNotFound) return }