// Code generated by Gosora's Router Generator. DO NOT EDIT. /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ package main import ( "log" "strings" "strconv" "compress/gzip" "sync" "sync/atomic" "errors" "os" "net/http" "github.com/Azareal/Gosora/common" "github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/routes" "github.com/Azareal/Gosora/routes/panel" ) var ErrNoRoute = errors.New("That route doesn't exist.") // TODO: What about the /uploads/ route? x.x var RouteMap = map[string]interface{}{ "routes.Overview": routes.Overview, "routes.CustomPage": routes.CustomPage, "routes.ForumList": routes.ForumList, "routes.ViewForum": routes.ViewForum, "routes.ChangeTheme": routes.ChangeTheme, "routes.ShowAttachment": routes.ShowAttachment, "common.RouteWebsockets": common.RouteWebsockets, "routeAPIPhrases": routeAPIPhrases, "routes.APIMe": routes.APIMe, "routeJSAntispam": routeJSAntispam, "routeAPI": routeAPI, "routes.ReportSubmit": routes.ReportSubmit, "routes.TopicListMostViewed": routes.TopicListMostViewed, "routes.CreateTopic": routes.CreateTopic, "routes.TopicList": routes.TopicList, "panel.Forums": panel.Forums, "panel.ForumsCreateSubmit": panel.ForumsCreateSubmit, "panel.ForumsDelete": panel.ForumsDelete, "panel.ForumsDeleteSubmit": panel.ForumsDeleteSubmit, "panel.ForumsEdit": panel.ForumsEdit, "panel.ForumsEditSubmit": panel.ForumsEditSubmit, "panel.ForumsEditPermsSubmit": panel.ForumsEditPermsSubmit, "panel.ForumsEditPermsAdvance": panel.ForumsEditPermsAdvance, "panel.ForumsEditPermsAdvanceSubmit": panel.ForumsEditPermsAdvanceSubmit, "panel.Settings": panel.Settings, "panel.SettingEdit": panel.SettingEdit, "panel.SettingEditSubmit": panel.SettingEditSubmit, "panel.WordFilters": panel.WordFilters, "panel.WordFiltersCreateSubmit": panel.WordFiltersCreateSubmit, "panel.WordFiltersEdit": panel.WordFiltersEdit, "panel.WordFiltersEditSubmit": panel.WordFiltersEditSubmit, "panel.WordFiltersDeleteSubmit": panel.WordFiltersDeleteSubmit, "panel.Pages": panel.Pages, "panel.PagesCreateSubmit": panel.PagesCreateSubmit, "panel.PagesEdit": panel.PagesEdit, "panel.PagesEditSubmit": panel.PagesEditSubmit, "panel.PagesDeleteSubmit": panel.PagesDeleteSubmit, "panel.Themes": panel.Themes, "panel.ThemesSetDefault": panel.ThemesSetDefault, "panel.ThemesMenus": panel.ThemesMenus, "panel.ThemesMenusEdit": panel.ThemesMenusEdit, "panel.ThemesMenuItemEdit": panel.ThemesMenuItemEdit, "panel.ThemesMenuItemEditSubmit": panel.ThemesMenuItemEditSubmit, "panel.ThemesMenuItemCreateSubmit": panel.ThemesMenuItemCreateSubmit, "panel.ThemesMenuItemDeleteSubmit": panel.ThemesMenuItemDeleteSubmit, "panel.ThemesMenuItemOrderSubmit": panel.ThemesMenuItemOrderSubmit, "panel.Plugins": panel.Plugins, "panel.PluginsActivate": panel.PluginsActivate, "panel.PluginsDeactivate": panel.PluginsDeactivate, "panel.PluginsInstall": panel.PluginsInstall, "panel.Users": panel.Users, "panel.UsersEdit": panel.UsersEdit, "panel.UsersEditSubmit": panel.UsersEditSubmit, "panel.AnalyticsViews": panel.AnalyticsViews, "panel.AnalyticsRoutes": panel.AnalyticsRoutes, "panel.AnalyticsAgents": panel.AnalyticsAgents, "panel.AnalyticsSystems": panel.AnalyticsSystems, "panel.AnalyticsLanguages": panel.AnalyticsLanguages, "panel.AnalyticsReferrers": panel.AnalyticsReferrers, "panel.AnalyticsRouteViews": panel.AnalyticsRouteViews, "panel.AnalyticsAgentViews": panel.AnalyticsAgentViews, "panel.AnalyticsForumViews": panel.AnalyticsForumViews, "panel.AnalyticsSystemViews": panel.AnalyticsSystemViews, "panel.AnalyticsLanguageViews": panel.AnalyticsLanguageViews, "panel.AnalyticsReferrerViews": panel.AnalyticsReferrerViews, "panel.AnalyticsPosts": panel.AnalyticsPosts, "panel.AnalyticsTopics": panel.AnalyticsTopics, "panel.AnalyticsForums": panel.AnalyticsForums, "panel.Groups": panel.Groups, "panel.GroupsEdit": panel.GroupsEdit, "panel.GroupsEditPerms": panel.GroupsEditPerms, "panel.GroupsEditSubmit": panel.GroupsEditSubmit, "panel.GroupsEditPermsSubmit": panel.GroupsEditPermsSubmit, "panel.GroupsCreateSubmit": panel.GroupsCreateSubmit, "panel.Backups": panel.Backups, "panel.LogsRegs": panel.LogsRegs, "panel.LogsMod": panel.LogsMod, "panel.Debug": panel.Debug, "panel.Dashboard": panel.Dashboard, "routes.AccountEdit": routes.AccountEdit, "routes.AccountEditPassword": routes.AccountEditPassword, "routes.AccountEditPasswordSubmit": routes.AccountEditPasswordSubmit, "routes.AccountEditAvatarSubmit": routes.AccountEditAvatarSubmit, "routes.AccountEditUsernameSubmit": routes.AccountEditUsernameSubmit, "routes.AccountEditMFA": routes.AccountEditMFA, "routes.AccountEditMFASetup": routes.AccountEditMFASetup, "routes.AccountEditMFASetupSubmit": routes.AccountEditMFASetupSubmit, "routes.AccountEditMFADisableSubmit": routes.AccountEditMFADisableSubmit, "routes.AccountEditEmail": routes.AccountEditEmail, "routes.AccountEditEmailTokenSubmit": routes.AccountEditEmailTokenSubmit, "routes.AccountLogins": routes.AccountLogins, "routes.LevelList": routes.LevelList, "routes.ViewProfile": routes.ViewProfile, "routes.BanUserSubmit": routes.BanUserSubmit, "routes.UnbanUser": routes.UnbanUser, "routes.ActivateUser": routes.ActivateUser, "routes.IPSearch": routes.IPSearch, "routes.CreateTopicSubmit": routes.CreateTopicSubmit, "routes.EditTopicSubmit": routes.EditTopicSubmit, "routes.DeleteTopicSubmit": routes.DeleteTopicSubmit, "routes.StickTopicSubmit": routes.StickTopicSubmit, "routes.UnstickTopicSubmit": routes.UnstickTopicSubmit, "routes.LockTopicSubmit": routes.LockTopicSubmit, "routes.UnlockTopicSubmit": routes.UnlockTopicSubmit, "routes.MoveTopicSubmit": routes.MoveTopicSubmit, "routes.LikeTopicSubmit": routes.LikeTopicSubmit, "routes.AddAttachToTopicSubmit": routes.AddAttachToTopicSubmit, "routes.RemoveAttachFromTopicSubmit": routes.RemoveAttachFromTopicSubmit, "routes.ViewTopic": routes.ViewTopic, "routes.CreateReplySubmit": routes.CreateReplySubmit, "routes.ReplyEditSubmit": routes.ReplyEditSubmit, "routes.ReplyDeleteSubmit": routes.ReplyDeleteSubmit, "routes.ReplyLikeSubmit": routes.ReplyLikeSubmit, "routes.ProfileReplyCreateSubmit": routes.ProfileReplyCreateSubmit, "routes.ProfileReplyEditSubmit": routes.ProfileReplyEditSubmit, "routes.ProfileReplyDeleteSubmit": routes.ProfileReplyDeleteSubmit, "routes.PollVote": routes.PollVote, "routes.PollResults": routes.PollResults, "routes.AccountLogin": routes.AccountLogin, "routes.AccountRegister": routes.AccountRegister, "routes.AccountLogout": routes.AccountLogout, "routes.AccountLoginSubmit": routes.AccountLoginSubmit, "routes.AccountLoginMFAVerify": routes.AccountLoginMFAVerify, "routes.AccountLoginMFAVerifySubmit": routes.AccountLoginMFAVerifySubmit, "routes.AccountRegisterSubmit": routes.AccountRegisterSubmit, "routes.DynamicRoute": routes.DynamicRoute, "routes.UploadedFile": routes.UploadedFile, "routes.StaticFile": routes.StaticFile, "routes.RobotsTxt": routes.RobotsTxt, "routes.SitemapXml": routes.SitemapXml, "routes.BadRoute": routes.BadRoute, } // ! NEVER RELY ON THESE REMAINING THE SAME BETWEEN COMMITS var routeMapEnum = map[string]int{ "routes.Overview": 0, "routes.CustomPage": 1, "routes.ForumList": 2, "routes.ViewForum": 3, "routes.ChangeTheme": 4, "routes.ShowAttachment": 5, "common.RouteWebsockets": 6, "routeAPIPhrases": 7, "routes.APIMe": 8, "routeJSAntispam": 9, "routeAPI": 10, "routes.ReportSubmit": 11, "routes.TopicListMostViewed": 12, "routes.CreateTopic": 13, "routes.TopicList": 14, "panel.Forums": 15, "panel.ForumsCreateSubmit": 16, "panel.ForumsDelete": 17, "panel.ForumsDeleteSubmit": 18, "panel.ForumsEdit": 19, "panel.ForumsEditSubmit": 20, "panel.ForumsEditPermsSubmit": 21, "panel.ForumsEditPermsAdvance": 22, "panel.ForumsEditPermsAdvanceSubmit": 23, "panel.Settings": 24, "panel.SettingEdit": 25, "panel.SettingEditSubmit": 26, "panel.WordFilters": 27, "panel.WordFiltersCreateSubmit": 28, "panel.WordFiltersEdit": 29, "panel.WordFiltersEditSubmit": 30, "panel.WordFiltersDeleteSubmit": 31, "panel.Pages": 32, "panel.PagesCreateSubmit": 33, "panel.PagesEdit": 34, "panel.PagesEditSubmit": 35, "panel.PagesDeleteSubmit": 36, "panel.Themes": 37, "panel.ThemesSetDefault": 38, "panel.ThemesMenus": 39, "panel.ThemesMenusEdit": 40, "panel.ThemesMenuItemEdit": 41, "panel.ThemesMenuItemEditSubmit": 42, "panel.ThemesMenuItemCreateSubmit": 43, "panel.ThemesMenuItemDeleteSubmit": 44, "panel.ThemesMenuItemOrderSubmit": 45, "panel.Plugins": 46, "panel.PluginsActivate": 47, "panel.PluginsDeactivate": 48, "panel.PluginsInstall": 49, "panel.Users": 50, "panel.UsersEdit": 51, "panel.UsersEditSubmit": 52, "panel.AnalyticsViews": 53, "panel.AnalyticsRoutes": 54, "panel.AnalyticsAgents": 55, "panel.AnalyticsSystems": 56, "panel.AnalyticsLanguages": 57, "panel.AnalyticsReferrers": 58, "panel.AnalyticsRouteViews": 59, "panel.AnalyticsAgentViews": 60, "panel.AnalyticsForumViews": 61, "panel.AnalyticsSystemViews": 62, "panel.AnalyticsLanguageViews": 63, "panel.AnalyticsReferrerViews": 64, "panel.AnalyticsPosts": 65, "panel.AnalyticsTopics": 66, "panel.AnalyticsForums": 67, "panel.Groups": 68, "panel.GroupsEdit": 69, "panel.GroupsEditPerms": 70, "panel.GroupsEditSubmit": 71, "panel.GroupsEditPermsSubmit": 72, "panel.GroupsCreateSubmit": 73, "panel.Backups": 74, "panel.LogsRegs": 75, "panel.LogsMod": 76, "panel.Debug": 77, "panel.Dashboard": 78, "routes.AccountEdit": 79, "routes.AccountEditPassword": 80, "routes.AccountEditPasswordSubmit": 81, "routes.AccountEditAvatarSubmit": 82, "routes.AccountEditUsernameSubmit": 83, "routes.AccountEditMFA": 84, "routes.AccountEditMFASetup": 85, "routes.AccountEditMFASetupSubmit": 86, "routes.AccountEditMFADisableSubmit": 87, "routes.AccountEditEmail": 88, "routes.AccountEditEmailTokenSubmit": 89, "routes.AccountLogins": 90, "routes.LevelList": 91, "routes.ViewProfile": 92, "routes.BanUserSubmit": 93, "routes.UnbanUser": 94, "routes.ActivateUser": 95, "routes.IPSearch": 96, "routes.CreateTopicSubmit": 97, "routes.EditTopicSubmit": 98, "routes.DeleteTopicSubmit": 99, "routes.StickTopicSubmit": 100, "routes.UnstickTopicSubmit": 101, "routes.LockTopicSubmit": 102, "routes.UnlockTopicSubmit": 103, "routes.MoveTopicSubmit": 104, "routes.LikeTopicSubmit": 105, "routes.AddAttachToTopicSubmit": 106, "routes.RemoveAttachFromTopicSubmit": 107, "routes.ViewTopic": 108, "routes.CreateReplySubmit": 109, "routes.ReplyEditSubmit": 110, "routes.ReplyDeleteSubmit": 111, "routes.ReplyLikeSubmit": 112, "routes.ProfileReplyCreateSubmit": 113, "routes.ProfileReplyEditSubmit": 114, "routes.ProfileReplyDeleteSubmit": 115, "routes.PollVote": 116, "routes.PollResults": 117, "routes.AccountLogin": 118, "routes.AccountRegister": 119, "routes.AccountLogout": 120, "routes.AccountLoginSubmit": 121, "routes.AccountLoginMFAVerify": 122, "routes.AccountLoginMFAVerifySubmit": 123, "routes.AccountRegisterSubmit": 124, "routes.DynamicRoute": 125, "routes.UploadedFile": 126, "routes.StaticFile": 127, "routes.RobotsTxt": 128, "routes.SitemapXml": 129, "routes.BadRoute": 130, } var reverseRouteMapEnum = map[int]string{ 0: "routes.Overview", 1: "routes.CustomPage", 2: "routes.ForumList", 3: "routes.ViewForum", 4: "routes.ChangeTheme", 5: "routes.ShowAttachment", 6: "common.RouteWebsockets", 7: "routeAPIPhrases", 8: "routes.APIMe", 9: "routeJSAntispam", 10: "routeAPI", 11: "routes.ReportSubmit", 12: "routes.TopicListMostViewed", 13: "routes.CreateTopic", 14: "routes.TopicList", 15: "panel.Forums", 16: "panel.ForumsCreateSubmit", 17: "panel.ForumsDelete", 18: "panel.ForumsDeleteSubmit", 19: "panel.ForumsEdit", 20: "panel.ForumsEditSubmit", 21: "panel.ForumsEditPermsSubmit", 22: "panel.ForumsEditPermsAdvance", 23: "panel.ForumsEditPermsAdvanceSubmit", 24: "panel.Settings", 25: "panel.SettingEdit", 26: "panel.SettingEditSubmit", 27: "panel.WordFilters", 28: "panel.WordFiltersCreateSubmit", 29: "panel.WordFiltersEdit", 30: "panel.WordFiltersEditSubmit", 31: "panel.WordFiltersDeleteSubmit", 32: "panel.Pages", 33: "panel.PagesCreateSubmit", 34: "panel.PagesEdit", 35: "panel.PagesEditSubmit", 36: "panel.PagesDeleteSubmit", 37: "panel.Themes", 38: "panel.ThemesSetDefault", 39: "panel.ThemesMenus", 40: "panel.ThemesMenusEdit", 41: "panel.ThemesMenuItemEdit", 42: "panel.ThemesMenuItemEditSubmit", 43: "panel.ThemesMenuItemCreateSubmit", 44: "panel.ThemesMenuItemDeleteSubmit", 45: "panel.ThemesMenuItemOrderSubmit", 46: "panel.Plugins", 47: "panel.PluginsActivate", 48: "panel.PluginsDeactivate", 49: "panel.PluginsInstall", 50: "panel.Users", 51: "panel.UsersEdit", 52: "panel.UsersEditSubmit", 53: "panel.AnalyticsViews", 54: "panel.AnalyticsRoutes", 55: "panel.AnalyticsAgents", 56: "panel.AnalyticsSystems", 57: "panel.AnalyticsLanguages", 58: "panel.AnalyticsReferrers", 59: "panel.AnalyticsRouteViews", 60: "panel.AnalyticsAgentViews", 61: "panel.AnalyticsForumViews", 62: "panel.AnalyticsSystemViews", 63: "panel.AnalyticsLanguageViews", 64: "panel.AnalyticsReferrerViews", 65: "panel.AnalyticsPosts", 66: "panel.AnalyticsTopics", 67: "panel.AnalyticsForums", 68: "panel.Groups", 69: "panel.GroupsEdit", 70: "panel.GroupsEditPerms", 71: "panel.GroupsEditSubmit", 72: "panel.GroupsEditPermsSubmit", 73: "panel.GroupsCreateSubmit", 74: "panel.Backups", 75: "panel.LogsRegs", 76: "panel.LogsMod", 77: "panel.Debug", 78: "panel.Dashboard", 79: "routes.AccountEdit", 80: "routes.AccountEditPassword", 81: "routes.AccountEditPasswordSubmit", 82: "routes.AccountEditAvatarSubmit", 83: "routes.AccountEditUsernameSubmit", 84: "routes.AccountEditMFA", 85: "routes.AccountEditMFASetup", 86: "routes.AccountEditMFASetupSubmit", 87: "routes.AccountEditMFADisableSubmit", 88: "routes.AccountEditEmail", 89: "routes.AccountEditEmailTokenSubmit", 90: "routes.AccountLogins", 91: "routes.LevelList", 92: "routes.ViewProfile", 93: "routes.BanUserSubmit", 94: "routes.UnbanUser", 95: "routes.ActivateUser", 96: "routes.IPSearch", 97: "routes.CreateTopicSubmit", 98: "routes.EditTopicSubmit", 99: "routes.DeleteTopicSubmit", 100: "routes.StickTopicSubmit", 101: "routes.UnstickTopicSubmit", 102: "routes.LockTopicSubmit", 103: "routes.UnlockTopicSubmit", 104: "routes.MoveTopicSubmit", 105: "routes.LikeTopicSubmit", 106: "routes.AddAttachToTopicSubmit", 107: "routes.RemoveAttachFromTopicSubmit", 108: "routes.ViewTopic", 109: "routes.CreateReplySubmit", 110: "routes.ReplyEditSubmit", 111: "routes.ReplyDeleteSubmit", 112: "routes.ReplyLikeSubmit", 113: "routes.ProfileReplyCreateSubmit", 114: "routes.ProfileReplyEditSubmit", 115: "routes.ProfileReplyDeleteSubmit", 116: "routes.PollVote", 117: "routes.PollResults", 118: "routes.AccountLogin", 119: "routes.AccountRegister", 120: "routes.AccountLogout", 121: "routes.AccountLoginSubmit", 122: "routes.AccountLoginMFAVerify", 123: "routes.AccountLoginMFAVerifySubmit", 124: "routes.AccountRegisterSubmit", 125: "routes.DynamicRoute", 126: "routes.UploadedFile", 127: "routes.StaticFile", 128: "routes.RobotsTxt", 129: "routes.SitemapXml", 130: "routes.BadRoute", } var osMapEnum = map[string]int{ "unknown": 0, "windows": 1, "linux": 2, "mac": 3, "android": 4, "iphone": 5, } var reverseOSMapEnum = map[int]string{ 0: "unknown", 1: "windows", 2: "linux", 3: "mac", 4: "android", 5: "iphone", } var agentMapEnum = map[string]int{ "unknown": 0, "firefox": 1, "chrome": 2, "opera": 3, "safari": 4, "edge": 5, "internetexplorer": 6, "trident": 7, "androidchrome": 8, "mobilesafari": 9, "samsung": 10, "ucbrowser": 11, "googlebot": 12, "yandex": 13, "bing": 14, "baidu": 15, "duckduckgo": 16, "seznambot": 17, "discord": 18, "twitter": 19, "cloudflare": 20, "uptimebot": 21, "slackbot": 22, "discourse": 23, "lynx": 24, "blank": 25, "malformed": 26, "suspicious": 27, "zgrab": 28, } var reverseAgentMapEnum = map[int]string{ 0: "unknown", 1: "firefox", 2: "chrome", 3: "opera", 4: "safari", 5: "edge", 6: "internetexplorer", 7: "trident", 8: "androidchrome", 9: "mobilesafari", 10: "samsung", 11: "ucbrowser", 12: "googlebot", 13: "yandex", 14: "bing", 15: "baidu", 16: "duckduckgo", 17: "seznambot", 18: "discord", 19: "twitter", 20: "cloudflare", 21: "uptimebot", 22: "slackbot", 23: "discourse", 24: "lynx", 25: "blank", 26: "malformed", 27: "suspicious", 28: "zgrab", } var markToAgent = map[string]string{ "OPR":"opera", "Chrome":"chrome", "Firefox":"firefox", "MSIE":"internetexplorer", "Trident":"trident", // Hack to support IE11 "Edge":"edge", "Lynx":"lynx", // There's a rare android variant of lynx which isn't covered by this "SamsungBrowser":"samsung", "UCBrowser":"ucbrowser", "Google":"googlebot", "Googlebot":"googlebot", "yandex": "yandex", // from the URL "DuckDuckBot":"duckduckgo", "Baiduspider":"baidu", "bingbot":"bing", "BingPreview":"bing", "SeznamBot":"seznambot", "CloudFlare":"cloudflare", // Track alwayson specifically in case there are other bots? "Uptimebot":"uptimebot", "Slackbot":"slackbot", "Discordbot":"discord", "Twitterbot":"twitter", "Discourse":"discourse", "zgrab":"zgrab", } /*var agentRank = map[string]int{ "opera":9, "chrome":8, "safari":1, }*/ // TODO: Stop spilling these into the package scope? func init() { counters.SetRouteMapEnum(routeMapEnum) counters.SetReverseRouteMapEnum(reverseRouteMapEnum) counters.SetAgentMapEnum(agentMapEnum) counters.SetReverseAgentMapEnum(reverseAgentMapEnum) counters.SetOSMapEnum(osMapEnum) counters.SetReverseOSMapEnum(reverseOSMapEnum) } type WriterIntercept struct { http.ResponseWriter } func NewWriterIntercept(w http.ResponseWriter) *WriterIntercept { return &WriterIntercept{w} } var wiMaxAge = "max-age=" + strconv.Itoa(int(common.Day)) func (writ *WriterIntercept) WriteHeader(code int) { if code == 200 { writ.ResponseWriter.Header().Set("Cache-Control", wiMaxAge) writ.ResponseWriter.Header().Set("Vary", "Accept-Encoding") } writ.ResponseWriter.WriteHeader(code) } type GenRouter struct { UploadHandler func(http.ResponseWriter, *http.Request) extraRoutes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError requestLogger *log.Logger sync.RWMutex } func NewGenRouter(uploads http.Handler) (*GenRouter, error) { f, err := os.OpenFile("./logs/requests.log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755) if err != nil { return nil, err } return &GenRouter{ UploadHandler: func(w http.ResponseWriter, req *http.Request) { writ := NewWriterIntercept(w) http.StripPrefix("/uploads/",uploads).ServeHTTP(writ,req) }, extraRoutes: make(map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError), requestLogger: log.New(f, "", log.LstdFlags), }, nil } func (r *GenRouter) handleError(err common.RouteError, w http.ResponseWriter, req *http.Request, user common.User) { if err.Handled() { return } if err.Type() == "system" { common.InternalErrorJSQ(err, w, req, err.JSON()) return } common.LocalErrorJSQ(err.Error(), w, req, user, err.JSON()) } func (r *GenRouter) Handle(_ string, _ http.Handler) { } func (r *GenRouter) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request, common.User) common.RouteError) { r.Lock() defer r.Unlock() r.extraRoutes[pattern] = handle } func (r *GenRouter) RemoveFunc(pattern string) error { r.Lock() defer r.Unlock() _, ok := r.extraRoutes[pattern] if !ok { return ErrNoRoute } delete(r.extraRoutes, pattern) return nil } func (r *GenRouter) DumpRequest(req *http.Request, prepend string) { var heads string for key, value := range req.Header { for _, vvalue := range value { heads += "Header '" + common.SanitiseSingleLine(key) + "': " + common.SanitiseSingleLine(vvalue) + "!!\n" } } r.requestLogger.Print(prepend + "\nUA: " + common.SanitiseSingleLine(req.UserAgent()) + "\n" + "Method: " + common.SanitiseSingleLine(req.Method) + "\n" + heads + "req.Host: " + common.SanitiseSingleLine(req.Host) + "\n" + "req.URL.Path: " + common.SanitiseSingleLine(req.URL.Path) + "\n" + "req.URL.RawQuery: " + common.SanitiseSingleLine(req.URL.RawQuery) + "\n" + "req.Referer(): " + common.SanitiseSingleLine(req.Referer()) + "\n" + "req.RemoteAddr: " + req.RemoteAddr + "\n") } func (r *GenRouter) SuspiciousRequest(req *http.Request, prepend string) { if prepend != "" { prepend += "\n" } r.DumpRequest(req,prepend+"Suspicious Request") counters.AgentViewCounter.Bump(27) } // TODO: Pass the default path or config struct to the router rather than accessing it via a package global // TODO: SetDefaultPath // TODO: GetDefaultPath func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Redirect www. requests to the right place if req.Host == "www." + common.Site.Host { w.Header().Set("Connection", "close") var s string if common.Site.EnableSsl { s = "s" } dest := "http"+s+"://" + common.Site.Host + req.URL.Path if len(req.URL.RawQuery) > 0 { dest += "?" + req.URL.RawQuery } http.Redirect(w, req, dest, http.StatusMovedPermanently) return } // Deflect malformed requests if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' || req.Host != common.Site.Host { w.WriteHeader(200) // 400 w.Write([]byte("")) r.DumpRequest(req,"Malformed Request") counters.AgentViewCounter.Bump(26) return } // TODO: Cover more suspicious strings and at a lower layer than this for _, char := range req.URL.Path { if char != '&' && !(char > 44 && char < 58) && char != '=' && char != '?' && !(char > 64 && char < 91) && char != '\\' && char != '_' && !(char > 96 && char < 123) { r.SuspiciousRequest(req,"Bad char in path") break } } lowerPath := strings.ToLower(req.URL.Path) // 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") { r.SuspiciousRequest(req,"Bad snippet in path") } // Indirect the default route onto a different one if req.URL.Path == "/" { req.URL.Path = common.Config.DefaultPath } var prefix, extraData string prefix = req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1] if req.URL.Path[len(req.URL.Path) - 1] != '/' { extraData = req.URL.Path[strings.LastIndexByte(req.URL.Path,'/') + 1:] req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1] } if prefix != "/ws" { h := w.Header() h.Set("X-Frame-Options", "deny") h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing // TODO: Set the content policy header h.Set("X-Content-Type-Options", "nosniff") } if common.Dev.SuperDebug { r.DumpRequest(req,"before routes.StaticFile") } // Increment the request counter counters.GlobalViewCounter.Bump() if prefix == "/static" { counters.RouteViewCounter.Bump(127) req.URL.Path += extraData routes.StaticFile(w, req) return } if atomic.LoadInt32(&common.IsDBDown) == 1 { common.DatabaseError(w, req) return } if common.Dev.SuperDebug { 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. // TODO: Add a setting to disable this? // TODO: Use a more efficient detector instead of smashing every possible combination in ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another if ua == "" { counters.AgentViewCounter.Bump(25) if common.Dev.DebugMode { var prepend string for _, char := range req.UserAgent() { prepend += strconv.Itoa(int(char)) + " " } r.DumpRequest(req,"Blank UA: " + prepend) } } else { var runeEquals = func(a []rune, b []rune) bool { if len(a) != len(b) { return false } for i, item := range a { if item != b[i] { return false } } return true } // WIP UA Parser var indices []int var items []string var buffer []rune for index, item := range ua { if (item > 64 && item < 91) || (item > 96 && item < 123) { buffer = append(buffer, item) } else if item == ' ' || item == '(' || item == ')' || item == '-' || (item > 47 && item < 58) || item == '_' || item == ';' || item == '.' || item == '+' || (item == ':' && (runeEquals(buffer,[]rune("http")) || runeEquals(buffer,[]rune("rv")))) || item == ',' || item == '/' { if len(buffer) != 0 { items = append(items, string(buffer)) indices = append(indices, index - 1) buffer = buffer[:0] } } else { // TODO: Test this items = items[:0] indices = indices[:0] r.SuspiciousRequest(req,"Illegal char in UA") r.requestLogger.Print("UA Buffer: ", buffer) r.requestLogger.Print("UA Buffer String: ", string(buffer)) break } } // Iterate over this in reverse as the real UA tends to be on the right side var agent string for i := len(items) - 1; i >= 0; i-- { fAgent, ok := markToAgent[items[i]] if ok { agent = fAgent if agent != "safari" { break } } } if common.Dev.SuperDebug { r.requestLogger.Print("parsed agent: ", agent) } var os string for _, mark := range items { switch(mark) { case "Windows": os = "windows" case "Linux": os = "linux" case "Mac": os = "mac" case "iPhone": os = "iphone" case "Android": os = "android" } } if os == "" { os = "unknown" } if common.Dev.SuperDebug { r.requestLogger.Print("os: ", os) r.requestLogger.Printf("items: %+v\n",items) } // Special handling switch(agent) { case "chrome": if os == "android" { agent = "androidchrome" } case "safari": if os == "iphone" { agent = "mobilesafari" } case "trident": // Hack to support IE11, change this after we start logging versions if strings.Contains(ua,"rv:11") { agent = "internetexplorer" } case "zgrab": r.SuspiciousRequest(req,"Vulnerability Scanner") } if agent == "" { counters.AgentViewCounter.Bump(0) if common.Dev.DebugMode { var prepend string for _, char := range req.UserAgent() { prepend += strconv.Itoa(int(char)) + " " } r.DumpRequest(req,"Blank UA: " + prepend) } } else { counters.AgentViewCounter.Bump(agentMapEnum[agent]) } counters.OSViewCounter.Bump(osMapEnum[os]) } // TODO: Do we want to track missing language headers too? Maybe as it's own type, e.g. "noheader"? lang := req.Header.Get("Accept-Language") if lang != "" { lang = strings.TrimSpace(lang) lLang := strings.Split(lang,"-") common.DebugDetail("lLang:", lLang) counters.LangViewCounter.Bump(lLang[0]) } else { counters.LangViewCounter.Bump("none") } referrer := req.Header.Get("Referer") // Check the 'referrer' header too? :P if referrer != "" { // ? Optimise this a little? referrer = strings.TrimPrefix(strings.TrimPrefix(referrer,"http://"),"https://") referrer = strings.Split(referrer,"/")[0] portless := strings.Split(referrer,":")[0] if portless != "localhost" && portless != "127.0.0.1" && portless != common.Site.Host { counters.ReferrerTracker.Bump(referrer) } } // Deal with the session stuff, etc. user, ok := common.PreRoute(w, req) if !ok { return } if common.Dev.SuperDebug { r.requestLogger.Print( "after PreRoute\n" + "routeMapEnum: ", routeMapEnum) } // Disable Gzip when SSL is disabled for security reasons? if prefix != "/ws" && strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") { w.Header().Set("Content-Encoding", "gzip") w.Header().Set("Content-Type", "text/html; charset=utf-8") gz := gzip.NewWriter(w) defer func() { if w.Header().Get("Content-Encoding") == "gzip" { gz.Close() } }() w = common.GzipResponseWriter{Writer: gz, ResponseWriter: w} } ferr := r.routeSwitch(w, req, user, prefix, extraData) if ferr != nil { r.handleError(ferr,w,req,user) } //common.StoppedServer("Profile end") } func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user common.User, prefix string, extraData string) common.RouteError { var err common.RouteError switch(prefix) { case "/overview": counters.RouteViewCounter.Bump(0) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.Overview(w,req,user,head) case "/pages": counters.RouteViewCounter.Bump(1) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.CustomPage(w,req,user,head,extraData) case "/forums": counters.RouteViewCounter.Bump(2) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.ForumList(w,req,user,head) case "/forum": counters.RouteViewCounter.Bump(3) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.ViewForum(w,req,user,head,extraData) case "/theme": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(4) err = routes.ChangeTheme(w,req,user) case "/attachs": err = common.ParseForm(w,req,user) if err != nil { return err } gzw, ok := w.(common.GzipResponseWriter) if ok { w = gzw.ResponseWriter w.Header().Del("Content-Type") w.Header().Del("Content-Encoding") } counters.RouteViewCounter.Bump(5) err = routes.ShowAttachment(w,req,user,extraData) case "/ws": req.URL.Path += extraData counters.RouteViewCounter.Bump(6) err = common.RouteWebsockets(w,req,user) case "/api": switch(req.URL.Path) { case "/api/phrases/": counters.RouteViewCounter.Bump(7) err = routeAPIPhrases(w,req,user) case "/api/me/": counters.RouteViewCounter.Bump(8) err = routes.APIMe(w,req,user) case "/api/watches/": counters.RouteViewCounter.Bump(9) err = routeJSAntispam(w,req,user) default: counters.RouteViewCounter.Bump(10) err = routeAPI(w,req,user) } case "/report": err = common.NoBanned(w,req,user) if err != nil { return err } switch(req.URL.Path) { case "/report/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(11) err = routes.ReportSubmit(w,req,user,extraData) } case "/topics": switch(req.URL.Path) { case "/topics/most-viewed/": counters.RouteViewCounter.Bump(12) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.TopicListMostViewed(w,req,user,head) case "/topics/create/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(13) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.CreateTopic(w,req,user,head,extraData) default: counters.RouteViewCounter.Bump(14) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.TopicList(w,req,user, head) } case "/panel": err = common.SuperModOnly(w,req,user) if err != nil { return err } switch(req.URL.Path) { case "/panel/forums/": counters.RouteViewCounter.Bump(15) err = panel.Forums(w,req,user) case "/panel/forums/create/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(16) err = panel.ForumsCreateSubmit(w,req,user) case "/panel/forums/delete/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(17) err = panel.ForumsDelete(w,req,user,extraData) case "/panel/forums/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(18) err = panel.ForumsDeleteSubmit(w,req,user,extraData) case "/panel/forums/edit/": counters.RouteViewCounter.Bump(19) err = panel.ForumsEdit(w,req,user,extraData) case "/panel/forums/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(20) err = panel.ForumsEditSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(21) err = panel.ForumsEditPermsSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/": counters.RouteViewCounter.Bump(22) err = panel.ForumsEditPermsAdvance(w,req,user,extraData) case "/panel/forums/edit/perms/adv/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(23) err = panel.ForumsEditPermsAdvanceSubmit(w,req,user,extraData) case "/panel/settings/": counters.RouteViewCounter.Bump(24) err = panel.Settings(w,req,user) case "/panel/settings/edit/": counters.RouteViewCounter.Bump(25) err = panel.SettingEdit(w,req,user,extraData) case "/panel/settings/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(26) err = panel.SettingEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/": counters.RouteViewCounter.Bump(27) err = panel.WordFilters(w,req,user) case "/panel/settings/word-filters/create/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(28) err = panel.WordFiltersCreateSubmit(w,req,user) case "/panel/settings/word-filters/edit/": counters.RouteViewCounter.Bump(29) err = panel.WordFiltersEdit(w,req,user,extraData) case "/panel/settings/word-filters/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(30) err = panel.WordFiltersEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(31) err = panel.WordFiltersDeleteSubmit(w,req,user,extraData) case "/panel/pages/": err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(32) err = panel.Pages(w,req,user) case "/panel/pages/create/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(33) err = panel.PagesCreateSubmit(w,req,user) case "/panel/pages/edit/": err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(34) err = panel.PagesEdit(w,req,user,extraData) case "/panel/pages/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(35) err = panel.PagesEditSubmit(w,req,user,extraData) case "/panel/pages/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(36) err = panel.PagesDeleteSubmit(w,req,user,extraData) case "/panel/themes/": counters.RouteViewCounter.Bump(37) err = panel.Themes(w,req,user) case "/panel/themes/default/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(38) err = panel.ThemesSetDefault(w,req,user,extraData) case "/panel/themes/menus/": counters.RouteViewCounter.Bump(39) err = panel.ThemesMenus(w,req,user) case "/panel/themes/menus/edit/": counters.RouteViewCounter.Bump(40) err = panel.ThemesMenusEdit(w,req,user,extraData) case "/panel/themes/menus/item/edit/": counters.RouteViewCounter.Bump(41) err = panel.ThemesMenuItemEdit(w,req,user,extraData) case "/panel/themes/menus/item/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(42) err = panel.ThemesMenuItemEditSubmit(w,req,user,extraData) case "/panel/themes/menus/item/create/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(43) err = panel.ThemesMenuItemCreateSubmit(w,req,user) case "/panel/themes/menus/item/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(44) err = panel.ThemesMenuItemDeleteSubmit(w,req,user,extraData) case "/panel/themes/menus/item/order/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(45) err = panel.ThemesMenuItemOrderSubmit(w,req,user,extraData) case "/panel/plugins/": counters.RouteViewCounter.Bump(46) err = panel.Plugins(w,req,user) case "/panel/plugins/activate/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(47) err = panel.PluginsActivate(w,req,user,extraData) case "/panel/plugins/deactivate/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(48) err = panel.PluginsDeactivate(w,req,user,extraData) case "/panel/plugins/install/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(49) err = panel.PluginsInstall(w,req,user,extraData) case "/panel/users/": counters.RouteViewCounter.Bump(50) err = panel.Users(w,req,user) case "/panel/users/edit/": counters.RouteViewCounter.Bump(51) err = panel.UsersEdit(w,req,user,extraData) case "/panel/users/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(52) err = panel.UsersEditSubmit(w,req,user,extraData) case "/panel/analytics/views/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(53) err = panel.AnalyticsViews(w,req,user) case "/panel/analytics/routes/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(54) err = panel.AnalyticsRoutes(w,req,user) case "/panel/analytics/agents/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(55) err = panel.AnalyticsAgents(w,req,user) case "/panel/analytics/systems/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(56) err = panel.AnalyticsSystems(w,req,user) case "/panel/analytics/langs/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(57) err = panel.AnalyticsLanguages(w,req,user) case "/panel/analytics/referrers/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(58) err = panel.AnalyticsReferrers(w,req,user) case "/panel/analytics/route/": counters.RouteViewCounter.Bump(59) err = panel.AnalyticsRouteViews(w,req,user,extraData) case "/panel/analytics/agent/": counters.RouteViewCounter.Bump(60) err = panel.AnalyticsAgentViews(w,req,user,extraData) case "/panel/analytics/forum/": counters.RouteViewCounter.Bump(61) err = panel.AnalyticsForumViews(w,req,user,extraData) case "/panel/analytics/system/": counters.RouteViewCounter.Bump(62) err = panel.AnalyticsSystemViews(w,req,user,extraData) case "/panel/analytics/lang/": counters.RouteViewCounter.Bump(63) err = panel.AnalyticsLanguageViews(w,req,user,extraData) case "/panel/analytics/referrer/": counters.RouteViewCounter.Bump(64) err = panel.AnalyticsReferrerViews(w,req,user,extraData) case "/panel/analytics/posts/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(65) err = panel.AnalyticsPosts(w,req,user) case "/panel/analytics/topics/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(66) err = panel.AnalyticsTopics(w,req,user) case "/panel/analytics/forums/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(67) err = panel.AnalyticsForums(w,req,user) case "/panel/groups/": counters.RouteViewCounter.Bump(68) err = panel.Groups(w,req,user) case "/panel/groups/edit/": counters.RouteViewCounter.Bump(69) err = panel.GroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": counters.RouteViewCounter.Bump(70) err = panel.GroupsEditPerms(w,req,user,extraData) case "/panel/groups/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(71) err = panel.GroupsEditSubmit(w,req,user,extraData) case "/panel/groups/edit/perms/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(72) err = panel.GroupsEditPermsSubmit(w,req,user,extraData) case "/panel/groups/create/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(73) err = panel.GroupsCreateSubmit(w,req,user) case "/panel/backups/": err = common.SuperAdminOnly(w,req,user) if err != nil { return err } gzw, ok := w.(common.GzipResponseWriter) if ok { w = gzw.ResponseWriter w.Header().Del("Content-Type") w.Header().Del("Content-Encoding") } counters.RouteViewCounter.Bump(74) err = panel.Backups(w,req,user,extraData) case "/panel/logs/regs/": counters.RouteViewCounter.Bump(75) err = panel.LogsRegs(w,req,user) case "/panel/logs/mod/": counters.RouteViewCounter.Bump(76) err = panel.LogsMod(w,req,user) case "/panel/debug/": err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(77) err = panel.Debug(w,req,user) default: counters.RouteViewCounter.Bump(78) err = panel.Dashboard(w,req,user) } case "/user": switch(req.URL.Path) { case "/user/edit/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(79) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEdit(w,req,user,head) case "/user/edit/password/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(80) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditPassword(w,req,user,head) case "/user/edit/password/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(81) err = routes.AccountEditPasswordSubmit(w,req,user) case "/user/edit/avatar/submit/": err = common.MemberOnly(w,req,user) if err != nil { return err } err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { return err } err = common.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(82) err = routes.AccountEditAvatarSubmit(w,req,user) case "/user/edit/username/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(83) err = routes.AccountEditUsernameSubmit(w,req,user) case "/user/edit/mfa/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(84) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditMFA(w,req,user,head) case "/user/edit/mfa/setup/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(85) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditMFASetup(w,req,user,head) case "/user/edit/mfa/setup/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(86) err = routes.AccountEditMFASetupSubmit(w,req,user) case "/user/edit/mfa/disable/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(87) err = routes.AccountEditMFADisableSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(88) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditEmail(w,req,user,head) case "/user/edit/token/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(89) err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData) case "/user/edit/logins/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(90) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountLogins(w,req,user,head) case "/user/levels/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(91) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.LevelList(w,req,user,head) default: req.URL.Path += extraData counters.RouteViewCounter.Bump(92) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.ViewProfile(w,req,user, head) } case "/users": switch(req.URL.Path) { case "/users/ban/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(93) err = routes.BanUserSubmit(w,req,user,extraData) case "/users/unban/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(94) err = routes.UnbanUser(w,req,user,extraData) case "/users/activate/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(95) err = routes.ActivateUser(w,req,user,extraData) case "/users/ips/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(96) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.IPSearch(w,req,user,head) } case "/topic": switch(req.URL.Path) { case "/topic/create/submit/": err = common.MemberOnly(w,req,user) if err != nil { return err } err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { return err } err = common.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(97) err = routes.CreateTopicSubmit(w,req,user) case "/topic/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(98) err = routes.EditTopicSubmit(w,req,user,extraData) case "/topic/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } req.URL.Path += extraData counters.RouteViewCounter.Bump(99) err = routes.DeleteTopicSubmit(w,req,user) case "/topic/stick/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(100) err = routes.StickTopicSubmit(w,req,user,extraData) case "/topic/unstick/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(101) err = routes.UnstickTopicSubmit(w,req,user,extraData) case "/topic/lock/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } req.URL.Path += extraData counters.RouteViewCounter.Bump(102) err = routes.LockTopicSubmit(w,req,user) case "/topic/unlock/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(103) err = routes.UnlockTopicSubmit(w,req,user,extraData) case "/topic/move/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(104) err = routes.MoveTopicSubmit(w,req,user,extraData) case "/topic/like/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(105) err = routes.LikeTopicSubmit(w,req,user,extraData) case "/topic/attach/add/submit/": err = common.MemberOnly(w,req,user) if err != nil { return err } err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { return err } err = common.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(106) err = routes.AddAttachToTopicSubmit(w,req,user,extraData) case "/topic/attach/remove/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(107) err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData) default: counters.RouteViewCounter.Bump(108) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.ViewTopic(w,req,user, head, extraData) } case "/reply": switch(req.URL.Path) { case "/reply/create/": err = common.MemberOnly(w,req,user) if err != nil { return err } err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { return err } err = common.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(109) err = routes.CreateReplySubmit(w,req,user) case "/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(110) err = routes.ReplyEditSubmit(w,req,user,extraData) case "/reply/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(111) err = routes.ReplyDeleteSubmit(w,req,user,extraData) case "/reply/like/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(112) err = routes.ReplyLikeSubmit(w,req,user,extraData) } case "/profile": switch(req.URL.Path) { case "/profile/reply/create/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(113) err = routes.ProfileReplyCreateSubmit(w,req,user) case "/profile/reply/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(114) err = routes.ProfileReplyEditSubmit(w,req,user,extraData) case "/profile/reply/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(115) err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData) } case "/poll": switch(req.URL.Path) { case "/poll/vote/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(116) err = routes.PollVote(w,req,user,extraData) case "/poll/results/": counters.RouteViewCounter.Bump(117) err = routes.PollResults(w,req,user,extraData) } case "/accounts": switch(req.URL.Path) { case "/accounts/login/": counters.RouteViewCounter.Bump(118) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountLogin(w,req,user,head) case "/accounts/create/": counters.RouteViewCounter.Bump(119) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountRegister(w,req,user,head) case "/accounts/logout/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(120) err = routes.AccountLogout(w,req,user) case "/accounts/login/submit/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(121) err = routes.AccountLoginSubmit(w,req,user) case "/accounts/mfa_verify/": counters.RouteViewCounter.Bump(122) head, err := common.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountLoginMFAVerify(w,req,user,head) case "/accounts/mfa_verify/submit/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(123) err = routes.AccountLoginMFAVerifySubmit(w,req,user) case "/accounts/create/submit/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(124) err = routes.AccountRegisterSubmit(w,req,user) } /*case "/sitemaps": // TODO: Count these views req.URL.Path += extraData err = sitemapSwitch(w,req)*/ case "/uploads": if extraData == "" { return common.NotFound(w,req,nil) } gzw, ok := w.(common.GzipResponseWriter) if ok { w = gzw.ResponseWriter w.Header().Del("Content-Type") w.Header().Del("Content-Encoding") } counters.RouteViewCounter.Bump(126) req.URL.Path += extraData // TODO: Find a way to propagate errors up from this? r.UploadHandler(w,req) // TODO: Count these views return nil case "": // Stop the favicons, robots.txt file, etc. resolving to the topics list // TODO: Add support for favicons and robots.txt files switch(extraData) { case "robots.txt": counters.RouteViewCounter.Bump(128) return routes.RobotsTxt(w,req) /*case "sitemap.xml": counters.RouteViewCounter.Bump(129) return routes.SitemapXml(w,req)*/ } return common.NotFound(w,req,nil) default: // A fallback for dynamic routes, e.g. ones declared by plugins r.RLock() handle, ok := r.extraRoutes[req.URL.Path] r.RUnlock() if ok { counters.RouteViewCounter.Bump(125) // TODO: Be more specific about *which* dynamic route it is req.URL.Path += extraData return handle(w,req,user) } 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") { r.SuspiciousRequest(req,"Bad Route") } else { r.DumpRequest(req,"Bad Route") } counters.RouteViewCounter.Bump(130) return common.NotFound(w,req,nil) } return err }