Fixing up some directory traversal attacks
This commit is contained in:
parent
b11be2f32c
commit
7a42f90b3f
@ -9,13 +9,25 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
ConfigType string
|
||||
ConfigType string
|
||||
|
||||
// ConfigEntry defines a single route configuration entry.
|
||||
// Used to configure routes from a JSON config file.
|
||||
ConfigEntry struct {
|
||||
ConfigType ConfigType
|
||||
UrlPattern string
|
||||
FileLocation string
|
||||
|
||||
// ConfigType indicates the type of route - Text, Image etc.
|
||||
ConfigType ConfigType
|
||||
|
||||
// UrlPattern is the URL regex pattern to match for the route.
|
||||
UrlPattern string
|
||||
|
||||
// FileLocation is the file path or directory to serve files from.
|
||||
FileLocation string
|
||||
|
||||
// UseBuiltinCache indicates whether to use the built-in LRU cache.
|
||||
UseBuiltinCache bool
|
||||
}
|
||||
|
||||
Config struct {
|
||||
ListeningAddress string
|
||||
Routes []ConfigEntry
|
||||
|
||||
@ -25,12 +25,19 @@ type ErrorResponse struct {
|
||||
}
|
||||
|
||||
type (
|
||||
// VinegarServlet is the main server struct that handles HTTP requests and routing.
|
||||
// It contains the TCP port to listen on, the routes to match requests against,
|
||||
// and a map of status code to error handling routes.
|
||||
VinegarServlet struct {
|
||||
Port string
|
||||
Routes []*VinegarRoute
|
||||
ErrorRoutes map[int]*TemplateRoute
|
||||
}
|
||||
|
||||
// VinegarRoute defines a single route in the router.
|
||||
// It contains a regex Pattern to match against the URL path,
|
||||
// a Handler function to call when the route matches,
|
||||
// and an optional Cache to enable caching for the route.
|
||||
VinegarRoute struct {
|
||||
Pattern *regexp.Regexp
|
||||
Handler VinegarHandlerFunction
|
||||
|
||||
@ -5,20 +5,67 @@ import (
|
||||
util "geniuscartel.xyz/vinegar/vinegarUtil"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// FileRoute implements a static file serving route.
|
||||
// It serves files from a given file path.
|
||||
FileRoute struct {
|
||||
*VinegarRoute
|
||||
srv *VinegarServlet
|
||||
|
||||
// VinegarRoute is the base route containing the URL pattern and handler.
|
||||
VinegarRoute *VinegarRoute
|
||||
|
||||
// srv is the VinegarServlet instance that this route is attached to.
|
||||
srv *VinegarServlet
|
||||
|
||||
// fileRoot is the base file path to serve files from.
|
||||
fileRoot string
|
||||
|
||||
// UseCache indicates whether to use caching for this route.
|
||||
UseCache bool
|
||||
}
|
||||
|
||||
//RouteConstructor
|
||||
//
|
||||
//Params:
|
||||
//
|
||||
//servlet - The VinegarServlet instance to add the route to
|
||||
//
|
||||
//urlPattern - The URL regex pattern for route to match
|
||||
//
|
||||
//pathlike - The file path to serve
|
||||
//
|
||||
//useCache - Whether to use caching for this route
|
||||
//
|
||||
// A RouteConstructor is a function that accepts a VinegarServlet, urlPattern, file path, and cache option. It uses
|
||||
// these to construct and return a FileRoute.
|
||||
// The return value is a FileRoute that will serve the files from the given path.
|
||||
//
|
||||
// This function signature allows encapsulating the creation of different types of FileRoutes. It is used to define
|
||||
// constructor functions for each file type, like NewTextRoute or NewImageRoute.
|
||||
RouteConstructor func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute
|
||||
)
|
||||
|
||||
// NewTextRoute creates a new FileRoute for serving text files.
|
||||
//
|
||||
// It handles text files as compressible content, gzipping them when the client sends the Accept-Encoding: gzip header.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// servlet - The VinegarServlet instance to attach the route to.
|
||||
//
|
||||
// urlPattern - The URL regex pattern that triggers this route.
|
||||
//
|
||||
// pathlike - The file path on disk to serve files from.
|
||||
//
|
||||
// useCache - Whether to use caching for this route.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// A FileRoute instance configured for serving text files, added to
|
||||
// the provided VinegarServlet.
|
||||
var NewTextRoute RouteConstructor = func(servlet *VinegarServlet, urlPattern string, pathlike string, useCache bool) *FileRoute {
|
||||
defaultPrune := strings.Replace(urlPattern, ".*", "", -1)
|
||||
route := FileRoute{srv: servlet, fileRoot: pathlike, UseCache: useCache}
|
||||
@ -61,6 +108,30 @@ var NewSingleFileRoute RouteConstructor = func(servlet *VinegarServlet, urlPatte
|
||||
return &route
|
||||
}
|
||||
|
||||
// createSingleFileServletFunction creates a handler function for serving a single file.
|
||||
//
|
||||
// It looks up the file content from the route's cache and writes the appropriate
|
||||
// headers and file content to the response.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// route - The FileRoute instance this handler is attached to.
|
||||
//
|
||||
// Returns:
|
||||
//
|
||||
// A VinegarHandlerFunction that serves the single file for the provided route.
|
||||
//
|
||||
// The handler function checks the route's cache for the file content.
|
||||
// If caching is enabled, it first checks the cache directly.
|
||||
// If caching is disabled, it calls GetFresh to avoid the cache.
|
||||
//
|
||||
// If the content is not found, it returns a 404 error.
|
||||
//
|
||||
// Otherwise, it sets the Content-Type header based on the cache's MIME type,
|
||||
// and writes the file content to the response.
|
||||
//
|
||||
// If the client accepts gzip encoding, it compresses the content before writing.
|
||||
|
||||
func createSingleFileServletFunction(route *FileRoute) VinegarHandlerFunction {
|
||||
|
||||
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
|
||||
@ -68,9 +139,9 @@ func createSingleFileServletFunction(route *FileRoute) VinegarHandlerFunction {
|
||||
var exists bool
|
||||
|
||||
if route.UseCache {
|
||||
cache, exists = route.Cache.Get("")
|
||||
cache, exists = route.VinegarRoute.Cache.Get("")
|
||||
} else {
|
||||
cache, exists = route.Cache.GetFresh("")
|
||||
cache, exists = route.VinegarRoute.Cache.GetFresh("")
|
||||
}
|
||||
|
||||
if !exists {
|
||||
@ -98,17 +169,17 @@ func createSingleFileServletFunction(route *FileRoute) VinegarHandlerFunction {
|
||||
func createCompressibleFileServletFunction(route *FileRoute, basePattern string, pathlike string) VinegarHandlerFunction {
|
||||
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
|
||||
stub := strings.Replace(req.URL.Path, basePattern, "", 1)
|
||||
cachedContent, exists := route.Cache.Get(stub)
|
||||
cachedContent, exists := route.VinegarRoute.Cache.Get(stub)
|
||||
//i don't like this logic below. we need to streamline this a lot better. it's a twisty jungle right now
|
||||
|
||||
resourcePath := path.Join(pathlike, stub)
|
||||
resourcePath := path.Join(pathlike, filepath.Clean(stub))
|
||||
|
||||
if !exists {
|
||||
content, fileExists := util.GetDiskContent(resourcePath)
|
||||
if fileExists {
|
||||
if route.UseCache {
|
||||
route.Cache.Put(stub, resourcePath)
|
||||
cachedContent, _ = route.Cache.Get(stub)
|
||||
route.VinegarRoute.Cache.Put(stub, resourcePath)
|
||||
cachedContent, _ = route.VinegarRoute.Cache.Get(stub)
|
||||
} else {
|
||||
w.Header().Add(ContentTypeHeaderKey, util.GuessMimetype(stub))
|
||||
w.Write(*content)
|
||||
@ -138,12 +209,12 @@ func createCompressibleFileServletFunction(route *FileRoute, basePattern string,
|
||||
|
||||
func createUncompressedFileServletFunction(route *FileRoute, basePattern string, pathlike string) VinegarHandlerFunction {
|
||||
var fun VinegarHandlerFunction = func(w http.ResponseWriter, req *http.Request) {
|
||||
stub := strings.Replace(req.URL.Path, basePattern, "", 1)
|
||||
stub := filepath.Clean(strings.Replace(req.URL.Path, basePattern, "", 1))
|
||||
resourcePath := path.Join(pathlike, stub)
|
||||
entry, exists := route.Cache.Get(stub)
|
||||
entry, exists := route.VinegarRoute.Cache.Get(stub)
|
||||
if !exists {
|
||||
route.Cache.Put(stub, resourcePath)
|
||||
entry, exists = route.Cache.Get(stub)
|
||||
route.VinegarRoute.Cache.Put(stub, resourcePath)
|
||||
entry, exists = route.VinegarRoute.Cache.Get(stub)
|
||||
}
|
||||
|
||||
if exists {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user