// 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" "bytes" "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.ThemesWidgets": panel.ThemesWidgets, "panel.ThemesWidgetsEditSubmit": panel.ThemesWidgetsEditSubmit, "panel.ThemesWidgetsCreateSubmit": panel.ThemesWidgetsCreateSubmit, "panel.ThemesWidgetsDeleteSubmit": panel.ThemesWidgetsDeleteSubmit, "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.AddAttachToReplySubmit": routes.AddAttachToReplySubmit, "routes.RemoveAttachFromReplySubmit": routes.RemoveAttachFromReplySubmit, "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.ThemesWidgets": 46, "panel.ThemesWidgetsEditSubmit": 47, "panel.ThemesWidgetsCreateSubmit": 48, "panel.ThemesWidgetsDeleteSubmit": 49, "panel.Plugins": 50, "panel.PluginsActivate": 51, "panel.PluginsDeactivate": 52, "panel.PluginsInstall": 53, "panel.Users": 54, "panel.UsersEdit": 55, "panel.UsersEditSubmit": 56, "panel.AnalyticsViews": 57, "panel.AnalyticsRoutes": 58, "panel.AnalyticsAgents": 59, "panel.AnalyticsSystems": 60, "panel.AnalyticsLanguages": 61, "panel.AnalyticsReferrers": 62, "panel.AnalyticsRouteViews": 63, "panel.AnalyticsAgentViews": 64, "panel.AnalyticsForumViews": 65, "panel.AnalyticsSystemViews": 66, "panel.AnalyticsLanguageViews": 67, "panel.AnalyticsReferrerViews": 68, "panel.AnalyticsPosts": 69, "panel.AnalyticsTopics": 70, "panel.AnalyticsForums": 71, "panel.Groups": 72, "panel.GroupsEdit": 73, "panel.GroupsEditPerms": 74, "panel.GroupsEditSubmit": 75, "panel.GroupsEditPermsSubmit": 76, "panel.GroupsCreateSubmit": 77, "panel.Backups": 78, "panel.LogsRegs": 79, "panel.LogsMod": 80, "panel.Debug": 81, "panel.Dashboard": 82, "routes.AccountEdit": 83, "routes.AccountEditPassword": 84, "routes.AccountEditPasswordSubmit": 85, "routes.AccountEditAvatarSubmit": 86, "routes.AccountEditUsernameSubmit": 87, "routes.AccountEditMFA": 88, "routes.AccountEditMFASetup": 89, "routes.AccountEditMFASetupSubmit": 90, "routes.AccountEditMFADisableSubmit": 91, "routes.AccountEditEmail": 92, "routes.AccountEditEmailTokenSubmit": 93, "routes.AccountLogins": 94, "routes.LevelList": 95, "routes.ViewProfile": 96, "routes.BanUserSubmit": 97, "routes.UnbanUser": 98, "routes.ActivateUser": 99, "routes.IPSearch": 100, "routes.CreateTopicSubmit": 101, "routes.EditTopicSubmit": 102, "routes.DeleteTopicSubmit": 103, "routes.StickTopicSubmit": 104, "routes.UnstickTopicSubmit": 105, "routes.LockTopicSubmit": 106, "routes.UnlockTopicSubmit": 107, "routes.MoveTopicSubmit": 108, "routes.LikeTopicSubmit": 109, "routes.AddAttachToTopicSubmit": 110, "routes.RemoveAttachFromTopicSubmit": 111, "routes.ViewTopic": 112, "routes.CreateReplySubmit": 113, "routes.ReplyEditSubmit": 114, "routes.ReplyDeleteSubmit": 115, "routes.ReplyLikeSubmit": 116, "routes.AddAttachToReplySubmit": 117, "routes.RemoveAttachFromReplySubmit": 118, "routes.ProfileReplyCreateSubmit": 119, "routes.ProfileReplyEditSubmit": 120, "routes.ProfileReplyDeleteSubmit": 121, "routes.PollVote": 122, "routes.PollResults": 123, "routes.AccountLogin": 124, "routes.AccountRegister": 125, "routes.AccountLogout": 126, "routes.AccountLoginSubmit": 127, "routes.AccountLoginMFAVerify": 128, "routes.AccountLoginMFAVerifySubmit": 129, "routes.AccountRegisterSubmit": 130, "routes.DynamicRoute": 131, "routes.UploadedFile": 132, "routes.StaticFile": 133, "routes.RobotsTxt": 134, "routes.SitemapXml": 135, "routes.BadRoute": 136, } 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.ThemesWidgets", 47: "panel.ThemesWidgetsEditSubmit", 48: "panel.ThemesWidgetsCreateSubmit", 49: "panel.ThemesWidgetsDeleteSubmit", 50: "panel.Plugins", 51: "panel.PluginsActivate", 52: "panel.PluginsDeactivate", 53: "panel.PluginsInstall", 54: "panel.Users", 55: "panel.UsersEdit", 56: "panel.UsersEditSubmit", 57: "panel.AnalyticsViews", 58: "panel.AnalyticsRoutes", 59: "panel.AnalyticsAgents", 60: "panel.AnalyticsSystems", 61: "panel.AnalyticsLanguages", 62: "panel.AnalyticsReferrers", 63: "panel.AnalyticsRouteViews", 64: "panel.AnalyticsAgentViews", 65: "panel.AnalyticsForumViews", 66: "panel.AnalyticsSystemViews", 67: "panel.AnalyticsLanguageViews", 68: "panel.AnalyticsReferrerViews", 69: "panel.AnalyticsPosts", 70: "panel.AnalyticsTopics", 71: "panel.AnalyticsForums", 72: "panel.Groups", 73: "panel.GroupsEdit", 74: "panel.GroupsEditPerms", 75: "panel.GroupsEditSubmit", 76: "panel.GroupsEditPermsSubmit", 77: "panel.GroupsCreateSubmit", 78: "panel.Backups", 79: "panel.LogsRegs", 80: "panel.LogsMod", 81: "panel.Debug", 82: "panel.Dashboard", 83: "routes.AccountEdit", 84: "routes.AccountEditPassword", 85: "routes.AccountEditPasswordSubmit", 86: "routes.AccountEditAvatarSubmit", 87: "routes.AccountEditUsernameSubmit", 88: "routes.AccountEditMFA", 89: "routes.AccountEditMFASetup", 90: "routes.AccountEditMFASetupSubmit", 91: "routes.AccountEditMFADisableSubmit", 92: "routes.AccountEditEmail", 93: "routes.AccountEditEmailTokenSubmit", 94: "routes.AccountLogins", 95: "routes.LevelList", 96: "routes.ViewProfile", 97: "routes.BanUserSubmit", 98: "routes.UnbanUser", 99: "routes.ActivateUser", 100: "routes.IPSearch", 101: "routes.CreateTopicSubmit", 102: "routes.EditTopicSubmit", 103: "routes.DeleteTopicSubmit", 104: "routes.StickTopicSubmit", 105: "routes.UnstickTopicSubmit", 106: "routes.LockTopicSubmit", 107: "routes.UnlockTopicSubmit", 108: "routes.MoveTopicSubmit", 109: "routes.LikeTopicSubmit", 110: "routes.AddAttachToTopicSubmit", 111: "routes.RemoveAttachFromTopicSubmit", 112: "routes.ViewTopic", 113: "routes.CreateReplySubmit", 114: "routes.ReplyEditSubmit", 115: "routes.ReplyDeleteSubmit", 116: "routes.ReplyLikeSubmit", 117: "routes.AddAttachToReplySubmit", 118: "routes.RemoveAttachFromReplySubmit", 119: "routes.ProfileReplyCreateSubmit", 120: "routes.ProfileReplyEditSubmit", 121: "routes.ProfileReplyDeleteSubmit", 122: "routes.PollVote", 123: "routes.PollResults", 124: "routes.AccountLogin", 125: "routes.AccountRegister", 126: "routes.AccountLogout", 127: "routes.AccountLoginSubmit", 128: "routes.AccountLoginMFAVerify", 129: "routes.AccountLoginMFAVerifySubmit", 130: "routes.AccountRegisterSubmit", 131: "routes.DynamicRoute", 132: "routes.UploadedFile", 133: "routes.StaticFile", 134: "routes.RobotsTxt", 135: "routes.SitemapXml", 136: "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, "semrush": 28, "dotbot": 29, "zgrab": 30, } 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: "semrush", 29: "dotbot", 30: "zgrab", } var markToAgent = map[string]string{ "OPR": "opera", "Chrome": "chrome", "Firefox": "firefox", "MSIE": "internetexplorer", "Trident": "trident", "Edge": "edge", "Lynx": "lynx", "SamsungBrowser": "samsung", "UCBrowser": "ucbrowser", "Google": "googlebot", "Googlebot": "googlebot", "yandex": "yandex", "DuckDuckBot": "duckduckgo", "Baiduspider": "baidu", "bingbot": "bing", "BingPreview": "bing", "SeznamBot": "seznambot", "CloudFlare": "cloudflare", "Uptimebot": "uptimebot", "Slackbot": "slackbot", "Discordbot": "discord", "Twitterbot": "twitter", "Discourse": "discourse", "SemrushBot": "semrush", "DotBot": "dotbot", "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/reqs-"+strconv.FormatInt(common.StartTime.Unix(),10)+".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(133) 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 { // WIP UA Parser var items []string var buffer []byte var os string for _, item := range StringToBytes(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 == '~' || (item == ':' && bytes.Equal(buffer,[]byte("http"))) || item == ',' || item == '/' { if len(buffer) != 0 { if len(buffer) > 2 { // Use an unsafe zero copy conversion here just to use the switch, it's not safe for this string to escape from here, as it will get mutated, so do a regular string conversion in append switch(BytesToString(buffer)) { case "Windows": os = "windows" case "Linux": os = "linux" case "Mac": os = "mac" case "iPhone": os = "iphone" case "Android": os = "android" case "like","compatible": // Skip these words default: items = append(items, string(buffer)) } } buffer = buffer[:0] } } else { // TODO: Test this items = items[:0] r.SuspiciousRequest(req,"Illegal char "+strconv.Itoa(int(item))+" in UA") r.requestLogger.Print("UA Buffer: ", buffer) r.requestLogger.Print("UA Buffer String: ", string(buffer)) break } } if os == "" { os = "unknown" } // 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) } 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) validCode := counters.LangViewCounter.Bump(lLang[0]) if !validCode { r.DumpRequest(req,"Invalid ISO Code") } } 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/themes/widgets/": counters.RouteViewCounter.Bump(46) err = panel.ThemesWidgets(w,req,user) case "/panel/themes/widgets/edit/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(47) err = panel.ThemesWidgetsEditSubmit(w,req,user,extraData) case "/panel/themes/widgets/create/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(48) err = panel.ThemesWidgetsCreateSubmit(w,req,user) case "/panel/themes/widgets/delete/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(49) err = panel.ThemesWidgetsDeleteSubmit(w,req,user,extraData) case "/panel/plugins/": counters.RouteViewCounter.Bump(50) err = panel.Plugins(w,req,user) case "/panel/plugins/activate/": err = common.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(51) 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(52) 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(53) err = panel.PluginsInstall(w,req,user,extraData) case "/panel/users/": counters.RouteViewCounter.Bump(54) err = panel.Users(w,req,user) case "/panel/users/edit/": counters.RouteViewCounter.Bump(55) 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(56) 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(57) err = panel.AnalyticsViews(w,req,user) case "/panel/analytics/routes/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(58) err = panel.AnalyticsRoutes(w,req,user) case "/panel/analytics/agents/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(59) err = panel.AnalyticsAgents(w,req,user) case "/panel/analytics/systems/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(60) err = panel.AnalyticsSystems(w,req,user) case "/panel/analytics/langs/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(61) err = panel.AnalyticsLanguages(w,req,user) case "/panel/analytics/referrers/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(62) err = panel.AnalyticsReferrers(w,req,user) case "/panel/analytics/route/": counters.RouteViewCounter.Bump(63) err = panel.AnalyticsRouteViews(w,req,user,extraData) case "/panel/analytics/agent/": counters.RouteViewCounter.Bump(64) err = panel.AnalyticsAgentViews(w,req,user,extraData) case "/panel/analytics/forum/": counters.RouteViewCounter.Bump(65) err = panel.AnalyticsForumViews(w,req,user,extraData) case "/panel/analytics/system/": counters.RouteViewCounter.Bump(66) err = panel.AnalyticsSystemViews(w,req,user,extraData) case "/panel/analytics/lang/": counters.RouteViewCounter.Bump(67) err = panel.AnalyticsLanguageViews(w,req,user,extraData) case "/panel/analytics/referrer/": counters.RouteViewCounter.Bump(68) 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(69) err = panel.AnalyticsPosts(w,req,user) case "/panel/analytics/topics/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(70) err = panel.AnalyticsTopics(w,req,user) case "/panel/analytics/forums/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(71) err = panel.AnalyticsForums(w,req,user) case "/panel/groups/": counters.RouteViewCounter.Bump(72) err = panel.Groups(w,req,user) case "/panel/groups/edit/": counters.RouteViewCounter.Bump(73) err = panel.GroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": counters.RouteViewCounter.Bump(74) 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(75) 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(76) 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(77) 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(78) err = panel.Backups(w,req,user,extraData) case "/panel/logs/regs/": counters.RouteViewCounter.Bump(79) err = panel.LogsRegs(w,req,user) case "/panel/logs/mod/": counters.RouteViewCounter.Bump(80) err = panel.LogsMod(w,req,user) case "/panel/debug/": err = common.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(81) err = panel.Debug(w,req,user) default: counters.RouteViewCounter.Bump(82) 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(83) 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(84) 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(85) 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(86) 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(87) err = routes.AccountEditUsernameSubmit(w,req,user) case "/user/edit/mfa/": 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.AccountEditMFA(w,req,user,head) case "/user/edit/mfa/setup/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(89) 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(90) 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(91) err = routes.AccountEditMFADisableSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(92) 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(93) 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(94) 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(95) 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(96) 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(97) 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(98) 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(99) err = routes.ActivateUser(w,req,user,extraData) case "/users/ips/": err = common.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(100) 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(101) 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(102) 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(103) 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(104) 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(105) 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(106) 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(107) 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(108) 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(109) 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(110) 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(111) err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData) default: counters.RouteViewCounter.Bump(112) 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(113) 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(114) 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(115) 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(116) err = routes.ReplyLikeSubmit(w,req,user,extraData) case "/reply/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(117) err = routes.AddAttachToReplySubmit(w,req,user,extraData) case "/reply/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(118) err = routes.RemoveAttachFromReplySubmit(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(119) 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(120) 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(121) 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(122) err = routes.PollVote(w,req,user,extraData) case "/poll/results/": counters.RouteViewCounter.Bump(123) err = routes.PollResults(w,req,user,extraData) } case "/accounts": switch(req.URL.Path) { case "/accounts/login/": counters.RouteViewCounter.Bump(124) 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(125) 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(126) err = routes.AccountLogout(w,req,user) case "/accounts/login/submit/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(127) err = routes.AccountLoginSubmit(w,req,user) case "/accounts/mfa_verify/": counters.RouteViewCounter.Bump(128) 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(129) err = routes.AccountLoginMFAVerifySubmit(w,req,user) case "/accounts/create/submit/": err = common.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(130) 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(132) 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(134) return routes.RobotsTxt(w,req) /*case "sitemap.xml": counters.RouteViewCounter.Bump(135) 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(131) // 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(136) return common.NotFound(w,req,nil) } return err }