The settings should be validated properly now when they're updated.

Added more features to RouteError and RouteErrorImpl to help in suppressing sensitive information.
Refactored the setting update logic, so the settings are reloaded all at once rather than updated individually.
Renamed the router variables in the generated router to r to reduce the number of characters we have to type there.
Renamed some of the r variables in the generated router to req for consistency sake.
This commit is contained in:
Azareal 2018-11-13 16:51:34 +10:00
parent 4040417320
commit 4759ec9c4c
5 changed files with 145 additions and 122 deletions

View File

@ -31,12 +31,16 @@ var tList []interface{}
type RouteError interface { type RouteError interface {
Type() string Type() string
Error() string Error() string
Cause() string
JSON() bool JSON() bool
Handled() bool Handled() bool
Wrap(string)
} }
type RouteErrorImpl struct { type RouteErrorImpl struct {
text string userText string
sysText string
system bool system bool
json bool json bool
handled bool handled bool
@ -51,7 +55,14 @@ func (err *RouteErrorImpl) Type() string {
} }
func (err *RouteErrorImpl) Error() string { func (err *RouteErrorImpl) Error() string {
return err.text return err.userText
}
func (err *RouteErrorImpl) Cause() string {
if err.sysText == "" {
return err.Error()
}
return err.sysText
} }
// Respond with JSON? // Respond with JSON?
@ -64,8 +75,30 @@ func (err *RouteErrorImpl) Handled() bool {
return err.handled return err.handled
} }
// Move the current error into the system error slot and add a new one to the user error slot to show the user
func (err *RouteErrorImpl) Wrap(userErr string) {
err.sysText = err.userText
err.userText = userErr
}
func HandledRouteError() RouteError { func HandledRouteError() RouteError {
return &RouteErrorImpl{"", false, false, true} return &RouteErrorImpl{"", "", false, false, true}
}
func Error(errmsg string) RouteError {
return &RouteErrorImpl{errmsg, "", false, false, false}
}
func FromError(err error) RouteError {
return &RouteErrorImpl{err.Error(), "", false, false, false}
}
func ErrorJSQ(errmsg string, isJs bool) RouteError {
return &RouteErrorImpl{errmsg, "", false, isJs, false}
}
func SysError(errmsg string) RouteError {
return &RouteErrorImpl{errmsg, errmsg, true, false, false}
} }
// LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future. // LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future.

View File

@ -78,18 +78,6 @@ func LoadSettings() error {
return nil return nil
} }
// nolint
var ErrNotInteger = errors.New("You were supposed to enter an integer x.x")
var ErrSettingNotInteger = errors.New("Only integers are allowed in this setting x.x")
var ErrBadConstraintNotInteger = errors.New("Invalid contraint! The constraint field wasn't an integer!")
var ErrBadSettingRange = errors.New("Only integers between a certain range are allowed in this setting")
// To avoid leaking internal state to the user
// TODO: We need to add some sort of DualError interface
func SafeSettingError(err error) bool {
return err == ErrNotInteger || err == ErrSettingNotInteger || err == ErrBadConstraintNotInteger || err == ErrBadSettingRange || err == ErrNoRows
}
// TODO: Add better support for HTML attributes (html-attribute). E.g. Meta descriptions. // TODO: Add better support for HTML attributes (html-attribute). E.g. Meta descriptions.
func (sBox SettingMap) ParseSetting(sname string, scontent string, stype string, constraint string) (err error) { func (sBox SettingMap) ParseSetting(sname string, scontent string, stype string, constraint string) (err error) {
var ssBox = map[string]interface{}(sBox) var ssBox = map[string]interface{}(sBox)
@ -99,12 +87,12 @@ func (sBox SettingMap) ParseSetting(sname string, scontent string, stype string,
case "int": case "int":
ssBox[sname], err = strconv.Atoi(scontent) ssBox[sname], err = strconv.Atoi(scontent)
if err != nil { if err != nil {
return ErrNotInteger return errors.New("You were supposed to enter an integer x.x")
} }
case "int64": case "int64":
ssBox[sname], err = strconv.ParseInt(scontent, 10, 64) ssBox[sname], err = strconv.ParseInt(scontent, 10, 64)
if err != nil { if err != nil {
return ErrNotInteger return errors.New("You were supposed to enter an integer x.x")
} }
case "list": case "list":
cons := strings.Split(constraint, "-") cons := strings.Split(constraint, "-")
@ -115,16 +103,16 @@ func (sBox SettingMap) ParseSetting(sname string, scontent string, stype string,
con1, err := strconv.Atoi(cons[0]) con1, err := strconv.Atoi(cons[0])
con2, err2 := strconv.Atoi(cons[1]) con2, err2 := strconv.Atoi(cons[1])
if err != nil || err2 != nil { if err != nil || err2 != nil {
return ErrBadConstraintNotInteger return errors.New("Invalid contraint! The constraint field wasn't an integer!")
} }
value, err := strconv.Atoi(scontent) value, err := strconv.Atoi(scontent)
if err != nil { if err != nil {
return ErrSettingNotInteger return errors.New("Only integers are allowed in this setting x.x")
} }
if value < con1 || value > con2 { if value < con1 || value > con2 {
return ErrBadSettingRange return errors.New("Only integers between a certain range are allowed in this setting")
} }
ssBox[sname] = value ssBox[sname] = value
default: default:
@ -157,10 +145,12 @@ func (sBox SettingMap) BypassGetAll() (settingList []*Setting, err error) {
return settingList, rows.Err() return settingList, rows.Err()
} }
func (sBox SettingMap) Update(name string, content string) error { func (sBox SettingMap) Update(name string, content string) RouteError {
setting, err := sBox.BypassGet(name) setting, err := sBox.BypassGet(name)
if err == ErrNoRows { if err == ErrNoRows {
return err return FromError(err)
} else if err != nil {
return SysError(err.Error())
} }
// TODO: Why is this here and not in a common function? // TODO: Why is this here and not in a common function?
@ -172,17 +162,20 @@ func (sBox SettingMap) Update(name string, content string) error {
} }
} }
err = sBox.ParseSetting(name, content, setting.Type, setting.Constraint)
if err != nil {
return FromError(err)
}
// TODO: Make this a method or function? // TODO: Make this a method or function?
_, err = settingStmts.update.Exec(content, name) _, err = settingStmts.update.Exec(content, name)
if err != nil { if err != nil {
return err return SysError(err.Error())
} }
err = sBox.ParseSetting(name, content, setting.Type, setting.Constraint) err = LoadSettings()
if err != nil { if err != nil {
return err return SysError(err.Error())
} }
// TODO: Do a reload instead?
SettingBox.Store(sBox)
return nil return nil
} }

View File

@ -585,39 +585,39 @@ func NewGenRouter(uploads http.Handler) (*GenRouter, error) {
}, nil }, nil
} }
func (router *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, r *http.Request, user common.User) { func (r *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, req *http.Request, user common.User) {
if err.Handled() { if err.Handled() {
return return
} }
if err.Type() == "system" { if err.Type() == "system" {
common.InternalErrorJSQ(err, w, r, err.JSON()) common.InternalErrorJSQ(err, w, req, err.JSON())
return return
} }
common.LocalErrorJSQ(err.Error(), w, r, user,err.JSON()) common.LocalErrorJSQ(err.Error(), w, req, user, err.JSON())
} }
func (router *GenRouter) Handle(_ string, _ http.Handler) { func (r *GenRouter) Handle(_ string, _ http.Handler) {
} }
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) { func (r *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) {
router.Lock() r.Lock()
defer router.Unlock() defer r.Unlock()
router.extraRoutes[pattern] = handle r.extraRoutes[pattern] = handle
} }
func (router *GenRouter) RemoveFunc(pattern string) error { func (r *GenRouter) RemoveFunc(pattern string) error {
router.Lock() r.Lock()
defer router.Unlock() defer r.Unlock()
_, ok := router.extraRoutes[pattern] _, ok := r.extraRoutes[pattern]
if !ok { if !ok {
return ErrNoRoute return ErrNoRoute
} }
delete(router.extraRoutes, pattern) delete(r.extraRoutes, pattern)
return nil return nil
} }
func (router *GenRouter) DumpRequest(req *http.Request, prepend string) { func (r *GenRouter) DumpRequest(req *http.Request, prepend string) {
var heads string var heads string
for key, value := range req.Header { for key, value := range req.Header {
for _, vvalue := range value { for _, vvalue := range value {
@ -625,7 +625,7 @@ func (router *GenRouter) DumpRequest(req *http.Request, prepend string) {
} }
} }
router.requestLogger.Print(prepend + r.requestLogger.Print(prepend +
"\nUA: " + common.SanitiseSingleLine(req.UserAgent()) + "\n" + "\nUA: " + common.SanitiseSingleLine(req.UserAgent()) + "\n" +
"Method: " + common.SanitiseSingleLine(req.Method) + "\n" + heads + "Method: " + common.SanitiseSingleLine(req.Method) + "\n" + heads +
"req.Host: " + common.SanitiseSingleLine(req.Host) + "\n" + "req.Host: " + common.SanitiseSingleLine(req.Host) + "\n" +
@ -635,18 +635,18 @@ func (router *GenRouter) DumpRequest(req *http.Request, prepend string) {
"req.RemoteAddr: " + req.RemoteAddr + "\n") "req.RemoteAddr: " + req.RemoteAddr + "\n")
} }
func (router *GenRouter) SuspiciousRequest(req *http.Request, prepend string) { func (r *GenRouter) SuspiciousRequest(req *http.Request, prepend string) {
if prepend != "" { if prepend != "" {
prepend += "\n" prepend += "\n"
} }
router.DumpRequest(req,prepend+"Suspicious Request") r.DumpRequest(req,prepend+"Suspicious Request")
counters.AgentViewCounter.Bump(27) counters.AgentViewCounter.Bump(27)
} }
// TODO: Pass the default path or config struct to the router rather than accessing it via a package global // TODO: Pass the default path or config struct to the router rather than accessing it via a package global
// TODO: SetDefaultPath // TODO: SetDefaultPath
// TODO: GetDefaultPath // TODO: GetDefaultPath
func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Redirect www. requests to the right place // Redirect www. requests to the right place
if req.Host == "www." + common.Site.Host { if req.Host == "www." + common.Site.Host {
w.Header().Set("Connection", "close") w.Header().Set("Connection", "close")
@ -666,7 +666,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' || req.Host != common.Site.Host { if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' || req.Host != common.Site.Host {
w.WriteHeader(200) // 400 w.WriteHeader(200) // 400
w.Write([]byte("")) w.Write([]byte(""))
router.DumpRequest(req,"Malformed Request") r.DumpRequest(req,"Malformed Request")
counters.AgentViewCounter.Bump(26) counters.AgentViewCounter.Bump(26)
return return
} }
@ -674,14 +674,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Cover more suspicious strings and at a lower layer than this // TODO: Cover more suspicious strings and at a lower layer than this
for _, char := range req.URL.Path { for _, char := range req.URL.Path {
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) {
router.SuspiciousRequest(req,"Bad char in path") r.SuspiciousRequest(req,"Bad char in path")
break break
} }
} }
lowerPath := strings.ToLower(req.URL.Path) lowerPath := strings.ToLower(req.URL.Path)
// TODO: Flag any requests which has a dot with anything but a number after that // TODO: Flag any requests which has a dot with anything but a number after that
if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") || strings.Contains(lowerPath,".php") || strings.Contains(lowerPath,".asp") || strings.Contains(lowerPath,".cgi") || strings.Contains(lowerPath,".py") || strings.Contains(lowerPath,".sql") || strings.Contains(lowerPath,".action") { if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") || strings.Contains(lowerPath,".php") || strings.Contains(lowerPath,".asp") || strings.Contains(lowerPath,".cgi") || strings.Contains(lowerPath,".py") || strings.Contains(lowerPath,".sql") || strings.Contains(lowerPath,".action") {
router.SuspiciousRequest(req,"Bad snippet in path") r.SuspiciousRequest(req,"Bad snippet in path")
} }
// Indirect the default route onto a different one // Indirect the default route onto a different one
@ -705,7 +705,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.DumpRequest(req,"before routes.StaticFile") r.DumpRequest(req,"before routes.StaticFile")
} }
// Increment the request counter // Increment the request counter
counters.GlobalViewCounter.Bump() counters.GlobalViewCounter.Bump()
@ -721,7 +721,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print("before PreRoute") r.requestLogger.Print("before PreRoute")
} }
// Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like. // Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like.
@ -735,7 +735,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
for _, char := range req.UserAgent() { for _, char := range req.UserAgent() {
prepend += strconv.Itoa(int(char)) + " " prepend += strconv.Itoa(int(char)) + " "
} }
router.DumpRequest(req,"Blank UA: " + prepend) r.DumpRequest(req,"Blank UA: " + prepend)
} }
} else { } else {
var runeEquals = func(a []rune, b []rune) bool { var runeEquals = func(a []rune, b []rune) bool {
@ -767,9 +767,9 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Test this // TODO: Test this
items = items[:0] items = items[:0]
indices = indices[:0] indices = indices[:0]
router.SuspiciousRequest(req,"Illegal char in UA") r.SuspiciousRequest(req,"Illegal char in UA")
router.requestLogger.Print("UA Buffer: ", buffer) r.requestLogger.Print("UA Buffer: ", buffer)
router.requestLogger.Print("UA Buffer String: ", string(buffer)) r.requestLogger.Print("UA Buffer String: ", string(buffer))
break break
} }
} }
@ -786,7 +786,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print("parsed agent: ", agent) r.requestLogger.Print("parsed agent: ", agent)
} }
var os string var os string
@ -808,8 +808,8 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
os = "unknown" os = "unknown"
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print("os: ", os) r.requestLogger.Print("os: ", os)
router.requestLogger.Printf("items: %+v\n",items) r.requestLogger.Printf("items: %+v\n",items)
} }
// Special handling // Special handling
@ -828,7 +828,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
agent = "internetexplorer" agent = "internetexplorer"
} }
case "zgrab": case "zgrab":
router.SuspiciousRequest(req,"Vulnerability Scanner") r.SuspiciousRequest(req,"Vulnerability Scanner")
} }
if agent == "" { if agent == "" {
@ -838,7 +838,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
for _, char := range req.UserAgent() { for _, char := range req.UserAgent() {
prepend += strconv.Itoa(int(char)) + " " prepend += strconv.Itoa(int(char)) + " "
} }
router.DumpRequest(req,"Blank UA: " + prepend) r.DumpRequest(req,"Blank UA: " + prepend)
} }
} else { } else {
counters.AgentViewCounter.Bump(agentMapEnum[agent]) counters.AgentViewCounter.Bump(agentMapEnum[agent])
@ -874,7 +874,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print( r.requestLogger.Print(
"after PreRoute\n" + "after PreRoute\n" +
"routeMapEnum: ", routeMapEnum) "routeMapEnum: ", routeMapEnum)
} }
@ -892,14 +892,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w = gzipResponseWriter{Writer: gz, ResponseWriter: w} w = gzipResponseWriter{Writer: gz, ResponseWriter: w}
} }
ferr := router.routeSwitch(w, req, user, prefix, extraData) ferr := r.routeSwitch(w, req, user, prefix, extraData)
if ferr != nil { if ferr != nil {
router.handleError(ferr,w,req,user) r.handleError(ferr,w,req,user)
} }
//common.StoppedServer("Profile end") //common.StoppedServer("Profile end")
} }
func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user common.User, prefix string, extraData string) common.RouteError { func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user common.User, prefix string, extraData string) common.RouteError {
var err common.RouteError var err common.RouteError
switch(prefix) { switch(prefix) {
case "/overview": case "/overview":
@ -1991,7 +1991,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
counters.RouteViewCounter.Bump(123) counters.RouteViewCounter.Bump(123)
req.URL.Path += extraData req.URL.Path += extraData
// TODO: Find a way to propagate errors up from this? // TODO: Find a way to propagate errors up from this?
router.UploadHandler(w,req) // TODO: Count these views r.UploadHandler(w,req) // TODO: Count these views
return nil return nil
case "": case "":
// Stop the favicons, robots.txt file, etc. resolving to the topics list // Stop the favicons, robots.txt file, etc. resolving to the topics list
@ -2006,10 +2006,10 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
} }
return common.NotFound(w,req,nil) return common.NotFound(w,req,nil)
default: default:
// A fallback for the routes which haven't been converted to the new router yet or plugins // A fallback for dynamic routes, e.g. ones declared by plugins
router.RLock() r.RLock()
handle, ok := router.extraRoutes[req.URL.Path] handle, ok := r.extraRoutes[req.URL.Path]
router.RUnlock() r.RUnlock()
if ok { if ok {
counters.RouteViewCounter.Bump(122) // TODO: Be more specific about *which* dynamic route it is counters.RouteViewCounter.Bump(122) // TODO: Be more specific about *which* dynamic route it is
@ -2019,9 +2019,9 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
lowerPath := strings.ToLower(req.URL.Path) lowerPath := strings.ToLower(req.URL.Path)
if strings.Contains(lowerPath,"admin") || strings.Contains(lowerPath,"sql") || strings.Contains(lowerPath,"manage") || strings.Contains(lowerPath,"//") || strings.Contains(lowerPath,"\\\\") || strings.Contains(lowerPath,"wp") || strings.Contains(lowerPath,"wordpress") || strings.Contains(lowerPath,"config") || strings.Contains(lowerPath,"setup") || strings.Contains(lowerPath,"install") || strings.Contains(lowerPath,"update") || strings.Contains(lowerPath,"php") { if strings.Contains(lowerPath,"admin") || strings.Contains(lowerPath,"sql") || strings.Contains(lowerPath,"manage") || strings.Contains(lowerPath,"//") || strings.Contains(lowerPath,"\\\\") || strings.Contains(lowerPath,"wp") || strings.Contains(lowerPath,"wordpress") || strings.Contains(lowerPath,"config") || strings.Contains(lowerPath,"setup") || strings.Contains(lowerPath,"install") || strings.Contains(lowerPath,"update") || strings.Contains(lowerPath,"php") {
router.SuspiciousRequest(req,"Bad Route") r.SuspiciousRequest(req,"Bad Route")
} else { } else {
router.DumpRequest(req,"Bad Route") r.DumpRequest(req,"Bad Route")
} }
counters.RouteViewCounter.Bump(127) counters.RouteViewCounter.Bump(127)
return common.NotFound(w,req,nil) return common.NotFound(w,req,nil)

View File

@ -367,39 +367,39 @@ func NewGenRouter(uploads http.Handler) (*GenRouter, error) {
}, nil }, nil
} }
func (router *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, r *http.Request, user common.User) { func (r *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, req *http.Request, user common.User) {
if err.Handled() { if err.Handled() {
return return
} }
if err.Type() == "system" { if err.Type() == "system" {
common.InternalErrorJSQ(err, w, r, err.JSON()) common.InternalErrorJSQ(err, w, req, err.JSON())
return return
} }
common.LocalErrorJSQ(err.Error(), w, r, user,err.JSON()) common.LocalErrorJSQ(err.Error(), w, req, user, err.JSON())
} }
func (router *GenRouter) Handle(_ string, _ http.Handler) { func (r *GenRouter) Handle(_ string, _ http.Handler) {
} }
func (router *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) { func (r *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) {
router.Lock() r.Lock()
defer router.Unlock() defer r.Unlock()
router.extraRoutes[pattern] = handle r.extraRoutes[pattern] = handle
} }
func (router *GenRouter) RemoveFunc(pattern string) error { func (r *GenRouter) RemoveFunc(pattern string) error {
router.Lock() r.Lock()
defer router.Unlock() defer r.Unlock()
_, ok := router.extraRoutes[pattern] _, ok := r.extraRoutes[pattern]
if !ok { if !ok {
return ErrNoRoute return ErrNoRoute
} }
delete(router.extraRoutes, pattern) delete(r.extraRoutes, pattern)
return nil return nil
} }
func (router *GenRouter) DumpRequest(req *http.Request, prepend string) { func (r *GenRouter) DumpRequest(req *http.Request, prepend string) {
var heads string var heads string
for key, value := range req.Header { for key, value := range req.Header {
for _, vvalue := range value { for _, vvalue := range value {
@ -407,7 +407,7 @@ func (router *GenRouter) DumpRequest(req *http.Request, prepend string) {
} }
} }
router.requestLogger.Print(prepend + r.requestLogger.Print(prepend +
"\nUA: " + common.SanitiseSingleLine(req.UserAgent()) + "\n" + "\nUA: " + common.SanitiseSingleLine(req.UserAgent()) + "\n" +
"Method: " + common.SanitiseSingleLine(req.Method) + "\n" + heads + "Method: " + common.SanitiseSingleLine(req.Method) + "\n" + heads +
"req.Host: " + common.SanitiseSingleLine(req.Host) + "\n" + "req.Host: " + common.SanitiseSingleLine(req.Host) + "\n" +
@ -417,18 +417,18 @@ func (router *GenRouter) DumpRequest(req *http.Request, prepend string) {
"req.RemoteAddr: " + req.RemoteAddr + "\n") "req.RemoteAddr: " + req.RemoteAddr + "\n")
} }
func (router *GenRouter) SuspiciousRequest(req *http.Request, prepend string) { func (r *GenRouter) SuspiciousRequest(req *http.Request, prepend string) {
if prepend != "" { if prepend != "" {
prepend += "\n" prepend += "\n"
} }
router.DumpRequest(req,prepend+"Suspicious Request") r.DumpRequest(req,prepend+"Suspicious Request")
counters.AgentViewCounter.Bump({{.AllAgentMap.suspicious}}) counters.AgentViewCounter.Bump({{.AllAgentMap.suspicious}})
} }
// TODO: Pass the default path or config struct to the router rather than accessing it via a package global // TODO: Pass the default path or config struct to the router rather than accessing it via a package global
// TODO: SetDefaultPath // TODO: SetDefaultPath
// TODO: GetDefaultPath // TODO: GetDefaultPath
func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Redirect www. requests to the right place // Redirect www. requests to the right place
if req.Host == "www." + common.Site.Host { if req.Host == "www." + common.Site.Host {
w.Header().Set("Connection", "close") w.Header().Set("Connection", "close")
@ -448,7 +448,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' || req.Host != common.Site.Host { if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' || req.Host != common.Site.Host {
w.WriteHeader(200) // 400 w.WriteHeader(200) // 400
w.Write([]byte("")) w.Write([]byte(""))
router.DumpRequest(req,"Malformed Request") r.DumpRequest(req,"Malformed Request")
counters.AgentViewCounter.Bump({{.AllAgentMap.malformed}}) counters.AgentViewCounter.Bump({{.AllAgentMap.malformed}})
return return
} }
@ -456,14 +456,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Cover more suspicious strings and at a lower layer than this // TODO: Cover more suspicious strings and at a lower layer than this
for _, char := range req.URL.Path { for _, char := range req.URL.Path {
if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) {
router.SuspiciousRequest(req,"Bad char in path") r.SuspiciousRequest(req,"Bad char in path")
break break
} }
} }
lowerPath := strings.ToLower(req.URL.Path) lowerPath := strings.ToLower(req.URL.Path)
// TODO: Flag any requests which has a dot with anything but a number after that // TODO: Flag any requests which has a dot with anything but a number after that
if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") || strings.Contains(lowerPath,".php") || strings.Contains(lowerPath,".asp") || strings.Contains(lowerPath,".cgi") || strings.Contains(lowerPath,".py") || strings.Contains(lowerPath,".sql") || strings.Contains(lowerPath,".action") { if strings.Contains(req.URL.Path,"..") || strings.Contains(req.URL.Path,"--") || strings.Contains(lowerPath,".php") || strings.Contains(lowerPath,".asp") || strings.Contains(lowerPath,".cgi") || strings.Contains(lowerPath,".py") || strings.Contains(lowerPath,".sql") || strings.Contains(lowerPath,".action") {
router.SuspiciousRequest(req,"Bad snippet in path") r.SuspiciousRequest(req,"Bad snippet in path")
} }
// Indirect the default route onto a different one // Indirect the default route onto a different one
@ -487,7 +487,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.DumpRequest(req,"before routes.StaticFile") r.DumpRequest(req,"before routes.StaticFile")
} }
// Increment the request counter // Increment the request counter
counters.GlobalViewCounter.Bump() counters.GlobalViewCounter.Bump()
@ -503,7 +503,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print("before PreRoute") r.requestLogger.Print("before PreRoute")
} }
// Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like. // Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like.
@ -517,7 +517,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
for _, char := range req.UserAgent() { for _, char := range req.UserAgent() {
prepend += strconv.Itoa(int(char)) + " " prepend += strconv.Itoa(int(char)) + " "
} }
router.DumpRequest(req,"Blank UA: " + prepend) r.DumpRequest(req,"Blank UA: " + prepend)
} }
} else { } else {
var runeEquals = func(a []rune, b []rune) bool { var runeEquals = func(a []rune, b []rune) bool {
@ -549,9 +549,9 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO: Test this // TODO: Test this
items = items[:0] items = items[:0]
indices = indices[:0] indices = indices[:0]
router.SuspiciousRequest(req,"Illegal char in UA") r.SuspiciousRequest(req,"Illegal char in UA")
router.requestLogger.Print("UA Buffer: ", buffer) r.requestLogger.Print("UA Buffer: ", buffer)
router.requestLogger.Print("UA Buffer String: ", string(buffer)) r.requestLogger.Print("UA Buffer String: ", string(buffer))
break break
} }
} }
@ -568,7 +568,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} }
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print("parsed agent: ", agent) r.requestLogger.Print("parsed agent: ", agent)
} }
var os string var os string
@ -590,8 +590,8 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
os = "unknown" os = "unknown"
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print("os: ", os) r.requestLogger.Print("os: ", os)
router.requestLogger.Printf("items: %+v\n",items) r.requestLogger.Printf("items: %+v\n",items)
} }
// Special handling // Special handling
@ -610,7 +610,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
agent = "internetexplorer" agent = "internetexplorer"
} }
case "zgrab": case "zgrab":
router.SuspiciousRequest(req,"Vulnerability Scanner") r.SuspiciousRequest(req,"Vulnerability Scanner")
} }
if agent == "" { if agent == "" {
@ -620,7 +620,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
for _, char := range req.UserAgent() { for _, char := range req.UserAgent() {
prepend += strconv.Itoa(int(char)) + " " prepend += strconv.Itoa(int(char)) + " "
} }
router.DumpRequest(req,"Blank UA: " + prepend) r.DumpRequest(req,"Blank UA: " + prepend)
} }
} else { } else {
counters.AgentViewCounter.Bump(agentMapEnum[agent]) counters.AgentViewCounter.Bump(agentMapEnum[agent])
@ -656,7 +656,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return return
} }
if common.Dev.SuperDebug { if common.Dev.SuperDebug {
router.requestLogger.Print( r.requestLogger.Print(
"after PreRoute\n" + "after PreRoute\n" +
"routeMapEnum: ", routeMapEnum) "routeMapEnum: ", routeMapEnum)
} }
@ -674,14 +674,14 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w = gzipResponseWriter{Writer: gz, ResponseWriter: w} w = gzipResponseWriter{Writer: gz, ResponseWriter: w}
} }
ferr := router.routeSwitch(w, req, user, prefix, extraData) ferr := r.routeSwitch(w, req, user, prefix, extraData)
if ferr != nil { if ferr != nil {
router.handleError(ferr,w,req,user) r.handleError(ferr,w,req,user)
} }
//common.StoppedServer("Profile end") //common.StoppedServer("Profile end")
} }
func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user common.User, prefix string, extraData string) common.RouteError { func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user common.User, prefix string, extraData string) common.RouteError {
var err common.RouteError var err common.RouteError
switch(prefix) {` + out + ` switch(prefix) {` + out + `
/*case "/sitemaps": // TODO: Count these views /*case "/sitemaps": // TODO: Count these views
@ -700,7 +700,7 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.UploadedFile" }}) counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.UploadedFile" }})
req.URL.Path += extraData req.URL.Path += extraData
// TODO: Find a way to propagate errors up from this? // TODO: Find a way to propagate errors up from this?
router.UploadHandler(w,req) // TODO: Count these views r.UploadHandler(w,req) // TODO: Count these views
return nil return nil
case "": case "":
// Stop the favicons, robots.txt file, etc. resolving to the topics list // Stop the favicons, robots.txt file, etc. resolving to the topics list
@ -715,10 +715,10 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
} }
return common.NotFound(w,req,nil) return common.NotFound(w,req,nil)
default: default:
// A fallback for the routes which haven't been converted to the new router yet or plugins // A fallback for dynamic routes, e.g. ones declared by plugins
router.RLock() r.RLock()
handle, ok := router.extraRoutes[req.URL.Path] handle, ok := r.extraRoutes[req.URL.Path]
router.RUnlock() r.RUnlock()
if ok { if ok {
counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.DynamicRoute" }}) // TODO: Be more specific about *which* dynamic route it is counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.DynamicRoute" }}) // TODO: Be more specific about *which* dynamic route it is
@ -728,9 +728,9 @@ func (router *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, u
lowerPath := strings.ToLower(req.URL.Path) lowerPath := strings.ToLower(req.URL.Path)
if strings.Contains(lowerPath,"admin") || strings.Contains(lowerPath,"sql") || strings.Contains(lowerPath,"manage") || strings.Contains(lowerPath,"//") || strings.Contains(lowerPath,"\\\\") || strings.Contains(lowerPath,"wp") || strings.Contains(lowerPath,"wordpress") || strings.Contains(lowerPath,"config") || strings.Contains(lowerPath,"setup") || strings.Contains(lowerPath,"install") || strings.Contains(lowerPath,"update") || strings.Contains(lowerPath,"php") { if strings.Contains(lowerPath,"admin") || strings.Contains(lowerPath,"sql") || strings.Contains(lowerPath,"manage") || strings.Contains(lowerPath,"//") || strings.Contains(lowerPath,"\\\\") || strings.Contains(lowerPath,"wp") || strings.Contains(lowerPath,"wordpress") || strings.Contains(lowerPath,"config") || strings.Contains(lowerPath,"setup") || strings.Contains(lowerPath,"install") || strings.Contains(lowerPath,"update") || strings.Contains(lowerPath,"php") {
router.SuspiciousRequest(req,"Bad Route") r.SuspiciousRequest(req,"Bad Route")
} else { } else {
router.DumpRequest(req,"Bad Route") r.DumpRequest(req,"Bad Route")
} }
counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.BadRoute" }}) counters.RouteViewCounter.Bump({{index .AllRouteMap "routes.BadRoute" }})
return common.NotFound(w,req,nil) return common.NotFound(w,req,nil)

View File

@ -102,12 +102,9 @@ func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user common.User,
} }
scontent := common.SanitiseBody(r.PostFormValue("setting-value")) scontent := common.SanitiseBody(r.PostFormValue("setting-value"))
err := headerLite.Settings.Update(sname, scontent) rerr := headerLite.Settings.Update(sname, scontent)
if err != nil { if rerr != nil {
if common.SafeSettingError(err) { return rerr
return common.LocalError(err.Error(), w, r, user)
}
return common.InternalError(err, w, r)
} }
http.Redirect(w, r, "/panel/settings/", http.StatusSeeOther) http.Redirect(w, r, "/panel/settings/", http.StatusSeeOther)