gophi/core/regex.go
kim (grufwub) 3ce4a5acf6 add support for hidden files regex (don't show in directory scans)
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
2020-10-21 23:54:45 +01:00

206 lines
5.8 KiB
Go

package core
import (
"path"
"regexp"
"strings"
)
var (
// cgiDir is a precompiled regex statement to check if a string matches the server's CGI directory
cgiDirRegex *regexp.Regexp
// WithinCGIDir returns whether a path is within the server's specified CGI scripts directory
WithinCGIDir func(*Path) bool
// restrictedPaths is the global slice of restricted paths
restrictedPaths []*regexp.Regexp
// IsRestrictedPath is the global function to check against restricted paths
IsRestrictedPath func(*Path) bool
// hiddenPaths is the global slice of hidden (from dir view) paths
hiddenPaths []*regexp.Regexp
// IsHiddenPath is the global function to check against hidden paths
IsHiddenPath func(*Path) bool
// requestRemaps is the global slice of remapped paths
requestRemaps []*RequestRemap
// RemapRequest is the global function to remap a request
RemapRequest func(*Request) bool
)
// PathMapSeparatorStr specifies the separator string to recognise in path mappings
const requestRemapSeparatorStr = " -> "
// RequestRemap is a structure to hold a remap regex to check against, and a template to apply this transformation onto
type RequestRemap struct {
Regex *regexp.Regexp
Template string
}
// compileCGIRegex takes a supplied string and returns compiled regular expression
func compileCGIRegex(cgiDir string) *regexp.Regexp {
if path.IsAbs(cgiDir) {
if !strings.HasPrefix(cgiDir, Root) {
SystemLog.Fatal(cgiDirOutsideRootStr)
}
} else {
cgiDir = path.Join(Root, cgiDir)
}
SystemLog.Info(cgiDirStr, cgiDir)
return regexp.MustCompile("(?m)" + cgiDir + "(|/.*)$")
}
// compileRestrictedPathsRegex turns a string of restricted paths into a slice of compiled regular expressions
func compileRestrictedPathsRegex(restrictions string) []*regexp.Regexp {
regexes := make([]*regexp.Regexp, 0)
// Split restrictions string by new lines
for _, expr := range strings.Split(restrictions, "\n") {
// Skip empty expressions
if len(expr) == 0 {
continue
}
// Compile the regular expression
regex, err := regexp.Compile("(?m)" + expr + "$")
if err != nil {
SystemLog.Fatal(pathRestrictRegexCompileFailStr, expr)
}
// Append compiled regex and log
regexes = append(regexes, regex)
SystemLog.Info(pathRestrictRegexCompiledStr, expr)
}
return regexes
}
// compileRestrictedPathsRegex turns a string of hidden paths into a slice of compiled regular expressions
func compileHiddenPathsRegex(hidden string) []*regexp.Regexp {
regexes := make([]*regexp.Regexp, 0)
// Split restrictions string by new lines
for _, expr := range strings.Split(hidden, "\n") {
// Skip empty expressions
if len(expr) == 0 {
continue
}
// Compile the regular expression
regex, err := regexp.Compile("(?m)" + expr + "$")
if err != nil {
SystemLog.Fatal(pathHidingRegexCompileFailStr, expr)
}
// Append compiled regex and log
regexes = append(regexes, regex)
SystemLog.Info(pathHidingRegexCompiledStr, expr)
}
return regexes
}
// compil RequestRemapRegex turns a string of remapped paths into a slice of compiled RequestRemap structures
func compileRequestRemapRegex(remaps string) []*RequestRemap {
requestRemaps := make([]*RequestRemap, 0)
// Split remaps string by new lines
for _, expr := range strings.Split(remaps, "\n") {
// Skip empty expressions
if len(expr) == 0 {
continue
}
// Split into alias and remap
split := strings.Split(expr, requestRemapSeparatorStr)
if len(split) != 2 {
SystemLog.Fatal(requestRemapRegexInvalidStr, expr)
}
// Compile the regular expression
regex, err := regexp.Compile("(?m)" + strings.TrimPrefix(split[0], "/") + "$")
if err != nil {
SystemLog.Fatal(requestRemapRegexCompileFailStr, expr)
}
// Append RequestRemap and log
requestRemaps = append(requestRemaps, &RequestRemap{regex, strings.TrimPrefix(split[1], "/")})
SystemLog.Info(requestRemapRegexCompiledStr, expr)
}
return requestRemaps
}
// withinCGIDirEnabled returns whether a Path's absolute value matches within the CGI dir
func withinCGIDirEnabled(p *Path) bool {
return cgiDirRegex.MatchString(p.Absolute())
}
// withinCGIDirDisabled always returns false, CGI is disabled
func withinCGIDirDisabled(p *Path) bool {
return false
}
// isRestrictedPathEnabled returns whether a Path's relative value is restricted
func isRestrictedPathEnabled(p *Path) bool {
for _, regex := range restrictedPaths {
if regex.MatchString(p.Selector()) {
return true
}
}
return false
}
// isRestrictedPathDisabled always returns false, there are no restricted paths
func isRestrictedPathDisabled(p *Path) bool {
return false
}
// isHiddenPathEnabled returns whether a Path's relative value should be hidden
func isHiddenPathEnabled(p *Path) bool {
for _, regex := range hiddenPaths {
if regex.MatchString(p.Selector()) {
return true
}
}
return false
}
// isHiddenPathDisabled always returns false, there are no hidden paths
func isHiddenPathDisabled(p *Path) bool {
return false
}
// remapRequestEnabled tries to remap a request, returning bool as to success
func remapRequestEnabled(request *Request) bool {
for _, remap := range requestRemaps {
// No match, gotta keep looking
if !remap.Regex.MatchString(request.Path().Selector()) {
continue
}
// Create new request from template and submatches
raw := make([]byte, 0)
for _, submatches := range remap.Regex.FindAllStringSubmatchIndex(request.Path().Selector(), -1) {
raw = remap.Regex.ExpandString(raw, remap.Template, request.Path().Selector(), submatches)
}
// Split to new path and paramters again
path, params := splitBy(string(raw), "?")
// Remap request, log, return
request.Remap(path, params)
return true
}
return false
}
// remapRequestDisabled always returns false, there are no remapped requests
func remapRequestDisabled(request *Request) bool {
return false
}