// 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" c "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": c.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.ForumsOrderSubmit": panel.ForumsOrderSubmit, "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.UsersAvatarSubmit": panel.UsersAvatarSubmit, "panel.UsersAvatarRemoveSubmit": panel.UsersAvatarRemoveSubmit, "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.AnalyticsMemory": panel.AnalyticsMemory, "panel.AnalyticsActiveMemory": panel.AnalyticsActiveMemory, "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.AccountEditRevokeAvatarSubmit": routes.AccountEditRevokeAvatarSubmit, "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.AccountPasswordReset": routes.AccountPasswordReset, "routes.AccountPasswordResetSubmit": routes.AccountPasswordResetSubmit, "routes.AccountPasswordResetToken": routes.AccountPasswordResetToken, "routes.AccountPasswordResetTokenSubmit": routes.AccountPasswordResetTokenSubmit, "routes.DynamicRoute": routes.DynamicRoute, "routes.UploadedFile": routes.UploadedFile, "routes.StaticFile": routes.StaticFile, "routes.RobotsTxt": routes.RobotsTxt, "routes.SitemapXml": routes.SitemapXml, "routes.OpenSearchXml": routes.OpenSearchXml, "routes.BadRoute": routes.BadRoute, "routes.HTTPSRedirect": routes.HTTPSRedirect, } // ! 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.ForumsOrderSubmit": 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.UsersAvatarSubmit": 58, "panel.UsersAvatarRemoveSubmit": 59, "panel.AnalyticsViews": 60, "panel.AnalyticsRoutes": 61, "panel.AnalyticsAgents": 62, "panel.AnalyticsSystems": 63, "panel.AnalyticsLanguages": 64, "panel.AnalyticsReferrers": 65, "panel.AnalyticsRouteViews": 66, "panel.AnalyticsAgentViews": 67, "panel.AnalyticsForumViews": 68, "panel.AnalyticsSystemViews": 69, "panel.AnalyticsLanguageViews": 70, "panel.AnalyticsReferrerViews": 71, "panel.AnalyticsPosts": 72, "panel.AnalyticsMemory": 73, "panel.AnalyticsActiveMemory": 74, "panel.AnalyticsTopics": 75, "panel.AnalyticsForums": 76, "panel.Groups": 77, "panel.GroupsEdit": 78, "panel.GroupsEditPerms": 79, "panel.GroupsEditSubmit": 80, "panel.GroupsEditPermsSubmit": 81, "panel.GroupsCreateSubmit": 82, "panel.Backups": 83, "panel.LogsRegs": 84, "panel.LogsMod": 85, "panel.Debug": 86, "panel.Dashboard": 87, "routes.AccountEdit": 88, "routes.AccountEditPassword": 89, "routes.AccountEditPasswordSubmit": 90, "routes.AccountEditAvatarSubmit": 91, "routes.AccountEditRevokeAvatarSubmit": 92, "routes.AccountEditUsernameSubmit": 93, "routes.AccountEditMFA": 94, "routes.AccountEditMFASetup": 95, "routes.AccountEditMFASetupSubmit": 96, "routes.AccountEditMFADisableSubmit": 97, "routes.AccountEditEmail": 98, "routes.AccountEditEmailTokenSubmit": 99, "routes.AccountLogins": 100, "routes.LevelList": 101, "routes.ViewProfile": 102, "routes.BanUserSubmit": 103, "routes.UnbanUser": 104, "routes.ActivateUser": 105, "routes.IPSearch": 106, "routes.CreateTopicSubmit": 107, "routes.EditTopicSubmit": 108, "routes.DeleteTopicSubmit": 109, "routes.StickTopicSubmit": 110, "routes.UnstickTopicSubmit": 111, "routes.LockTopicSubmit": 112, "routes.UnlockTopicSubmit": 113, "routes.MoveTopicSubmit": 114, "routes.LikeTopicSubmit": 115, "routes.AddAttachToTopicSubmit": 116, "routes.RemoveAttachFromTopicSubmit": 117, "routes.ViewTopic": 118, "routes.CreateReplySubmit": 119, "routes.ReplyEditSubmit": 120, "routes.ReplyDeleteSubmit": 121, "routes.ReplyLikeSubmit": 122, "routes.AddAttachToReplySubmit": 123, "routes.RemoveAttachFromReplySubmit": 124, "routes.ProfileReplyCreateSubmit": 125, "routes.ProfileReplyEditSubmit": 126, "routes.ProfileReplyDeleteSubmit": 127, "routes.PollVote": 128, "routes.PollResults": 129, "routes.AccountLogin": 130, "routes.AccountRegister": 131, "routes.AccountLogout": 132, "routes.AccountLoginSubmit": 133, "routes.AccountLoginMFAVerify": 134, "routes.AccountLoginMFAVerifySubmit": 135, "routes.AccountRegisterSubmit": 136, "routes.AccountPasswordReset": 137, "routes.AccountPasswordResetSubmit": 138, "routes.AccountPasswordResetToken": 139, "routes.AccountPasswordResetTokenSubmit": 140, "routes.DynamicRoute": 141, "routes.UploadedFile": 142, "routes.StaticFile": 143, "routes.RobotsTxt": 144, "routes.SitemapXml": 145, "routes.OpenSearchXml": 146, "routes.BadRoute": 147, "routes.HTTPSRedirect": 148, } 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.ForumsOrderSubmit", 20: "panel.ForumsEdit", 21: "panel.ForumsEditSubmit", 22: "panel.ForumsEditPermsSubmit", 23: "panel.ForumsEditPermsAdvance", 24: "panel.ForumsEditPermsAdvanceSubmit", 25: "panel.Settings", 26: "panel.SettingEdit", 27: "panel.SettingEditSubmit", 28: "panel.WordFilters", 29: "panel.WordFiltersCreateSubmit", 30: "panel.WordFiltersEdit", 31: "panel.WordFiltersEditSubmit", 32: "panel.WordFiltersDeleteSubmit", 33: "panel.Pages", 34: "panel.PagesCreateSubmit", 35: "panel.PagesEdit", 36: "panel.PagesEditSubmit", 37: "panel.PagesDeleteSubmit", 38: "panel.Themes", 39: "panel.ThemesSetDefault", 40: "panel.ThemesMenus", 41: "panel.ThemesMenusEdit", 42: "panel.ThemesMenuItemEdit", 43: "panel.ThemesMenuItemEditSubmit", 44: "panel.ThemesMenuItemCreateSubmit", 45: "panel.ThemesMenuItemDeleteSubmit", 46: "panel.ThemesMenuItemOrderSubmit", 47: "panel.ThemesWidgets", 48: "panel.ThemesWidgetsEditSubmit", 49: "panel.ThemesWidgetsCreateSubmit", 50: "panel.ThemesWidgetsDeleteSubmit", 51: "panel.Plugins", 52: "panel.PluginsActivate", 53: "panel.PluginsDeactivate", 54: "panel.PluginsInstall", 55: "panel.Users", 56: "panel.UsersEdit", 57: "panel.UsersEditSubmit", 58: "panel.UsersAvatarSubmit", 59: "panel.UsersAvatarRemoveSubmit", 60: "panel.AnalyticsViews", 61: "panel.AnalyticsRoutes", 62: "panel.AnalyticsAgents", 63: "panel.AnalyticsSystems", 64: "panel.AnalyticsLanguages", 65: "panel.AnalyticsReferrers", 66: "panel.AnalyticsRouteViews", 67: "panel.AnalyticsAgentViews", 68: "panel.AnalyticsForumViews", 69: "panel.AnalyticsSystemViews", 70: "panel.AnalyticsLanguageViews", 71: "panel.AnalyticsReferrerViews", 72: "panel.AnalyticsPosts", 73: "panel.AnalyticsMemory", 74: "panel.AnalyticsActiveMemory", 75: "panel.AnalyticsTopics", 76: "panel.AnalyticsForums", 77: "panel.Groups", 78: "panel.GroupsEdit", 79: "panel.GroupsEditPerms", 80: "panel.GroupsEditSubmit", 81: "panel.GroupsEditPermsSubmit", 82: "panel.GroupsCreateSubmit", 83: "panel.Backups", 84: "panel.LogsRegs", 85: "panel.LogsMod", 86: "panel.Debug", 87: "panel.Dashboard", 88: "routes.AccountEdit", 89: "routes.AccountEditPassword", 90: "routes.AccountEditPasswordSubmit", 91: "routes.AccountEditAvatarSubmit", 92: "routes.AccountEditRevokeAvatarSubmit", 93: "routes.AccountEditUsernameSubmit", 94: "routes.AccountEditMFA", 95: "routes.AccountEditMFASetup", 96: "routes.AccountEditMFASetupSubmit", 97: "routes.AccountEditMFADisableSubmit", 98: "routes.AccountEditEmail", 99: "routes.AccountEditEmailTokenSubmit", 100: "routes.AccountLogins", 101: "routes.LevelList", 102: "routes.ViewProfile", 103: "routes.BanUserSubmit", 104: "routes.UnbanUser", 105: "routes.ActivateUser", 106: "routes.IPSearch", 107: "routes.CreateTopicSubmit", 108: "routes.EditTopicSubmit", 109: "routes.DeleteTopicSubmit", 110: "routes.StickTopicSubmit", 111: "routes.UnstickTopicSubmit", 112: "routes.LockTopicSubmit", 113: "routes.UnlockTopicSubmit", 114: "routes.MoveTopicSubmit", 115: "routes.LikeTopicSubmit", 116: "routes.AddAttachToTopicSubmit", 117: "routes.RemoveAttachFromTopicSubmit", 118: "routes.ViewTopic", 119: "routes.CreateReplySubmit", 120: "routes.ReplyEditSubmit", 121: "routes.ReplyDeleteSubmit", 122: "routes.ReplyLikeSubmit", 123: "routes.AddAttachToReplySubmit", 124: "routes.RemoveAttachFromReplySubmit", 125: "routes.ProfileReplyCreateSubmit", 126: "routes.ProfileReplyEditSubmit", 127: "routes.ProfileReplyDeleteSubmit", 128: "routes.PollVote", 129: "routes.PollResults", 130: "routes.AccountLogin", 131: "routes.AccountRegister", 132: "routes.AccountLogout", 133: "routes.AccountLoginSubmit", 134: "routes.AccountLoginMFAVerify", 135: "routes.AccountLoginMFAVerifySubmit", 136: "routes.AccountRegisterSubmit", 137: "routes.AccountPasswordReset", 138: "routes.AccountPasswordResetSubmit", 139: "routes.AccountPasswordResetToken", 140: "routes.AccountPasswordResetTokenSubmit", 141: "routes.DynamicRoute", 142: "routes.UploadedFile", 143: "routes.StaticFile", 144: "routes.RobotsTxt", 145: "routes.SitemapXml", 146: "routes.OpenSearchXml", 147: "routes.BadRoute", 148: "routes.HTTPSRedirect", } 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, "facebook": 20, "cloudflare": 21, "uptimebot": 22, "slackbot": 23, "apple": 24, "discourse": 25, "lynx": 26, "blank": 27, "malformed": 28, "suspicious": 29, "semrush": 30, "dotbot": 31, "zgrab": 32, } 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: "facebook", 21: "cloudflare", 22: "uptimebot", 23: "slackbot", 24: "apple", 25: "discourse", 26: "lynx", 27: "blank", 28: "malformed", 29: "suspicious", 30: "semrush", 31: "dotbot", 32: "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", "facebookexternalhit": "facebook", "Facebot": "facebook", "Applebot": "apple", "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(c.Day)) func (writ *WriterIntercept) WriteHeader(code int) { if code == 200 { h := writ.ResponseWriter.Header() h.Set("Cache-Control", wiMaxAge) h.Set("Vary", "Accept-Encoding") } writ.ResponseWriter.WriteHeader(code) } // HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS type HTTPSRedirect struct {} func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Header().Set("Connection", "close") counters.RouteViewCounter.Bump(148) dest := "https://" + req.Host + req.URL.String() http.Redirect(w, req, dest, http.StatusTemporaryRedirect) } type GenRouter struct { UploadHandler func(http.ResponseWriter, *http.Request) extraRoutes map[string]func(http.ResponseWriter, *http.Request, c.User) c.RouteError requestLogger *log.Logger sync.RWMutex } func NewGenRouter(uploads http.Handler) (*GenRouter, error) { f, err := os.OpenFile("./logs/reqs-"+strconv.FormatInt(c.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, c.User) c.RouteError), requestLogger: log.New(f, "", log.LstdFlags), }, nil } func (r *GenRouter) handleError(err c.RouteError, w http.ResponseWriter, req *http.Request, user c.User) { if err.Handled() { return } if err.Type() == "system" { c.InternalErrorJSQ(err, w, req, err.JSON()) return } c.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, c.User) c.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 '" + c.SanitiseSingleLine(key) + "': " + c.SanitiseSingleLine(vvalue) + "!\n" } } r.requestLogger.Print(prepend + "\nUA: " + c.SanitiseSingleLine(req.UserAgent()) + "\n" + "Method: " + c.SanitiseSingleLine(req.Method) + "\n" + heads + "req.Host: " + c.SanitiseSingleLine(req.Host) + "\n" + "req.URL.Path: " + c.SanitiseSingleLine(req.URL.Path) + "\n" + "req.URL.RawQuery: " + c.SanitiseSingleLine(req.URL.RawQuery) + "\n" + "req.Referer(): " + c.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(29) } func isLocalHost(host string) bool { return host=="localhost" || host=="127.0.0.1" || host=="::1" } // 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) { var malformedRequest = func(typ int) { w.WriteHeader(200) // 400 w.Write([]byte("")) r.DumpRequest(req,"Malformed Request T"+strconv.Itoa(typ)) counters.AgentViewCounter.Bump(28) } // Split the Host and Port string var shost, sport string if req.Host[0]=='[' { spl := strings.Split(req.Host,"]") if len(spl) > 2 { malformedRequest(0) return } shost = strings.TrimPrefix(spl[0],"[") sport = strings.TrimPrefix(spl[1],":") } else { spl := strings.Split(req.Host,":") if len(spl) > 2 { malformedRequest(1) return } shost = spl[0] if len(spl)==2 { sport = spl[1] } } // TODO: Reject requests from non-local IPs, if the site host is set to localhost or a localhost IP if !c.Config.LoosePort && c.Site.PortInt != 80 && c.Site.PortInt != 443 && sport != c.Site.Port { malformedRequest(2) return } // Redirect www. and local IP requests to the right place if shost == "www." + c.Site.Host || (c.Site.LocalHost && shost != c.Site.Host && isLocalHost(shost)) { // TODO: Abstract the redirect logic? w.Header().Set("Connection", "close") var s string if c.Site.EnableSsl { s = "s" } var p string if c.Site.PortInt != 80 && c.Site.PortInt != 443 { p = ":"+c.Site.Port } dest := "http"+s+"://" + c.Site.Host+p + 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] != '/' || (!c.Config.LooseHost && shost != c.Site.Host) { malformedRequest(3) return } if c.Dev.FullReqLog { r.DumpRequest(req,"") } // 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 = c.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] } // TODO: Use the same hook table as downstream hTbl := c.GetHookTable() skip, ferr := hTbl.VhookSkippable("router_after_filters", w, req, prefix, extraData) if skip || ferr != nil { return } 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 h.Set("X-Content-Type-Options", "nosniff") } if c.Dev.SuperDebug { r.DumpRequest(req,"before routes.StaticFile") } // Increment the request counter counters.GlobalViewCounter.Bump() if prefix == "/static" { counters.RouteViewCounter.Bump(143) req.URL.Path += extraData routes.StaticFile(w, req) return } if atomic.LoadInt32(&c.IsDBDown) == 1 { c.DatabaseError(w, req) return } if c.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 var agent string if ua == "" { counters.AgentViewCounter.Bump(27) if c.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 == '~' || 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 for i := len(items) - 1; i >= 0; i-- { fAgent, ok := markToAgent[items[i]] if ok { agent = fAgent if agent != "safari" { break } } } if c.Dev.SuperDebug { r.requestLogger.Print("parsed agent: ", agent) } if c.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 c.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,"-") tLang := strings.Split(strings.Split(lLang[0],";")[0],",") c.DebugDetail("tLang:", tLang) var llLang string for _, seg := range tLang { if seg == "*" { continue } llLang = seg break } c.DebugDetail("llLang:", llLang) if llLang == "" { counters.LangViewCounter.Bump("none") } else { validCode := counters.LangViewCounter.Bump(llLang) 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 != c.Site.Host { counters.ReferrerTracker.Bump(referrer) } } // Deal with the session stuff, etc. user, ok := c.PreRoute(w, req) if !ok { return } user.LastAgent = agent if c.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") { h := w.Header() h.Set("Content-Encoding", "gzip") h.Set("Content-Type", "text/html; charset=utf-8") gzw := c.GzipResponseWriter{Writer: gzip.NewWriter(w), ResponseWriter: w} defer func() { if h.Get("Content-Encoding") == "gzip" && h.Get("X-I") == "" { gzw.Writer.(*gzip.Writer).Close() } }() w = gzw } skip, ferr = hTbl.VhookSkippable("router_pre_route", w, req, user, prefix, extraData) if skip || ferr != nil { r.handleError(ferr,w,req,user) } ferr = r.routeSwitch(w, req, user, prefix, extraData) if ferr != nil { r.handleError(ferr,w,req,user) } hTbl.VhookNoRet("router_end", w, req, user, prefix, extraData) //c.StoppedServer("Profile end") } func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c.User, prefix string, extraData string) c.RouteError { var err c.RouteError switch(prefix) { case "/overview": counters.RouteViewCounter.Bump(0) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.Overview(w,req,user,head) case "/pages": counters.RouteViewCounter.Bump(1) head, err := c.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 := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.ForumList(w,req,user,head) case "/forum": counters.RouteViewCounter.Bump(3) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.ViewForum(w,req,user,head,extraData) case "/theme": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(4) err = routes.ChangeTheme(w,req,user) case "/attachs": err = c.ParseForm(w,req,user) if err != nil { return err } gzw, ok := w.(c.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 = c.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 = c.NoBanned(w,req,user) if err != nil { return err } switch(req.URL.Path) { case "/report/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.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 := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.TopicListMostViewed(w,req,user,head) case "/topics/create/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(13) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.CreateTopic(w,req,user,head,extraData) default: counters.RouteViewCounter.Bump(14) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.TopicList(w,req,user, head) } case "/panel": err = c.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 = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(16) err = panel.ForumsCreateSubmit(w,req,user) case "/panel/forums/delete/": err = c.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 = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(18) err = panel.ForumsDeleteSubmit(w,req,user,extraData) case "/panel/forums/order/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(19) err = panel.ForumsOrderSubmit(w,req,user) case "/panel/forums/edit/": counters.RouteViewCounter.Bump(20) err = panel.ForumsEdit(w,req,user,extraData) case "/panel/forums/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(21) err = panel.ForumsEditSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(22) err = panel.ForumsEditPermsSubmit(w,req,user,extraData) case "/panel/forums/edit/perms/": counters.RouteViewCounter.Bump(23) err = panel.ForumsEditPermsAdvance(w,req,user,extraData) case "/panel/forums/edit/perms/adv/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(24) err = panel.ForumsEditPermsAdvanceSubmit(w,req,user,extraData) case "/panel/settings/": counters.RouteViewCounter.Bump(25) err = panel.Settings(w,req,user) case "/panel/settings/edit/": counters.RouteViewCounter.Bump(26) err = panel.SettingEdit(w,req,user,extraData) case "/panel/settings/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(27) err = panel.SettingEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/": counters.RouteViewCounter.Bump(28) err = panel.WordFilters(w,req,user) case "/panel/settings/word-filters/create/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(29) err = panel.WordFiltersCreateSubmit(w,req,user) case "/panel/settings/word-filters/edit/": counters.RouteViewCounter.Bump(30) err = panel.WordFiltersEdit(w,req,user,extraData) case "/panel/settings/word-filters/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(31) err = panel.WordFiltersEditSubmit(w,req,user,extraData) case "/panel/settings/word-filters/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(32) err = panel.WordFiltersDeleteSubmit(w,req,user,extraData) case "/panel/pages/": err = c.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(33) err = panel.Pages(w,req,user) case "/panel/pages/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(34) err = panel.PagesCreateSubmit(w,req,user) case "/panel/pages/edit/": err = c.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(35) err = panel.PagesEdit(w,req,user,extraData) case "/panel/pages/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(36) err = panel.PagesEditSubmit(w,req,user,extraData) case "/panel/pages/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(37) err = panel.PagesDeleteSubmit(w,req,user,extraData) case "/panel/themes/": counters.RouteViewCounter.Bump(38) err = panel.Themes(w,req,user) case "/panel/themes/default/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(39) err = panel.ThemesSetDefault(w,req,user,extraData) case "/panel/themes/menus/": counters.RouteViewCounter.Bump(40) err = panel.ThemesMenus(w,req,user) case "/panel/themes/menus/edit/": counters.RouteViewCounter.Bump(41) err = panel.ThemesMenusEdit(w,req,user,extraData) case "/panel/themes/menus/item/edit/": counters.RouteViewCounter.Bump(42) err = panel.ThemesMenuItemEdit(w,req,user,extraData) case "/panel/themes/menus/item/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(43) err = panel.ThemesMenuItemEditSubmit(w,req,user,extraData) case "/panel/themes/menus/item/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(44) err = panel.ThemesMenuItemCreateSubmit(w,req,user) case "/panel/themes/menus/item/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(45) err = panel.ThemesMenuItemDeleteSubmit(w,req,user,extraData) case "/panel/themes/menus/item/order/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(46) err = panel.ThemesMenuItemOrderSubmit(w,req,user,extraData) case "/panel/themes/widgets/": counters.RouteViewCounter.Bump(47) err = panel.ThemesWidgets(w,req,user) case "/panel/themes/widgets/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(48) err = panel.ThemesWidgetsEditSubmit(w,req,user,extraData) case "/panel/themes/widgets/create/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(49) err = panel.ThemesWidgetsCreateSubmit(w,req,user) case "/panel/themes/widgets/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(50) err = panel.ThemesWidgetsDeleteSubmit(w,req,user,extraData) case "/panel/plugins/": counters.RouteViewCounter.Bump(51) err = panel.Plugins(w,req,user) case "/panel/plugins/activate/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(52) err = panel.PluginsActivate(w,req,user,extraData) case "/panel/plugins/deactivate/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(53) err = panel.PluginsDeactivate(w,req,user,extraData) case "/panel/plugins/install/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(54) err = panel.PluginsInstall(w,req,user,extraData) case "/panel/users/": counters.RouteViewCounter.Bump(55) err = panel.Users(w,req,user) case "/panel/users/edit/": counters.RouteViewCounter.Bump(56) err = panel.UsersEdit(w,req,user,extraData) case "/panel/users/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(57) err = panel.UsersEditSubmit(w,req,user,extraData) case "/panel/users/avatar/submit/": err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { return err } err = c.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(58) err = panel.UsersAvatarSubmit(w,req,user,extraData) case "/panel/users/avatar/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(59) err = panel.UsersAvatarRemoveSubmit(w,req,user,extraData) case "/panel/analytics/views/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(60) err = panel.AnalyticsViews(w,req,user) case "/panel/analytics/routes/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(61) err = panel.AnalyticsRoutes(w,req,user) case "/panel/analytics/agents/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(62) err = panel.AnalyticsAgents(w,req,user) case "/panel/analytics/systems/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(63) err = panel.AnalyticsSystems(w,req,user) case "/panel/analytics/langs/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(64) err = panel.AnalyticsLanguages(w,req,user) case "/panel/analytics/referrers/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(65) err = panel.AnalyticsReferrers(w,req,user) case "/panel/analytics/route/": counters.RouteViewCounter.Bump(66) err = panel.AnalyticsRouteViews(w,req,user,extraData) case "/panel/analytics/agent/": counters.RouteViewCounter.Bump(67) err = panel.AnalyticsAgentViews(w,req,user,extraData) case "/panel/analytics/forum/": counters.RouteViewCounter.Bump(68) err = panel.AnalyticsForumViews(w,req,user,extraData) case "/panel/analytics/system/": counters.RouteViewCounter.Bump(69) err = panel.AnalyticsSystemViews(w,req,user,extraData) case "/panel/analytics/lang/": counters.RouteViewCounter.Bump(70) err = panel.AnalyticsLanguageViews(w,req,user,extraData) case "/panel/analytics/referrer/": counters.RouteViewCounter.Bump(71) err = panel.AnalyticsReferrerViews(w,req,user,extraData) case "/panel/analytics/posts/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(72) err = panel.AnalyticsPosts(w,req,user) case "/panel/analytics/memory/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(73) err = panel.AnalyticsMemory(w,req,user) case "/panel/analytics/active-memory/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(74) err = panel.AnalyticsActiveMemory(w,req,user) case "/panel/analytics/topics/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(75) err = panel.AnalyticsTopics(w,req,user) case "/panel/analytics/forums/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(76) err = panel.AnalyticsForums(w,req,user) case "/panel/groups/": counters.RouteViewCounter.Bump(77) err = panel.Groups(w,req,user) case "/panel/groups/edit/": counters.RouteViewCounter.Bump(78) err = panel.GroupsEdit(w,req,user,extraData) case "/panel/groups/edit/perms/": counters.RouteViewCounter.Bump(79) err = panel.GroupsEditPerms(w,req,user,extraData) case "/panel/groups/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(80) err = panel.GroupsEditSubmit(w,req,user,extraData) case "/panel/groups/edit/perms/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(81) err = panel.GroupsEditPermsSubmit(w,req,user,extraData) case "/panel/groups/create/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(82) err = panel.GroupsCreateSubmit(w,req,user) case "/panel/backups/": err = c.SuperAdminOnly(w,req,user) if err != nil { return err } gzw, ok := w.(c.GzipResponseWriter) if ok { w = gzw.ResponseWriter w.Header().Del("Content-Type") w.Header().Del("Content-Encoding") } counters.RouteViewCounter.Bump(83) err = panel.Backups(w,req,user,extraData) case "/panel/logs/regs/": counters.RouteViewCounter.Bump(84) err = panel.LogsRegs(w,req,user) case "/panel/logs/mod/": counters.RouteViewCounter.Bump(85) err = panel.LogsMod(w,req,user) case "/panel/debug/": err = c.AdminOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(86) err = panel.Debug(w,req,user) default: counters.RouteViewCounter.Bump(87) err = panel.Dashboard(w,req,user) } case "/user": switch(req.URL.Path) { case "/user/edit/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(88) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEdit(w,req,user,head) case "/user/edit/password/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(89) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditPassword(w,req,user,head) case "/user/edit/password/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(90) err = routes.AccountEditPasswordSubmit(w,req,user) case "/user/edit/avatar/submit/": err = c.MemberOnly(w,req,user) if err != nil { return err } err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { return err } err = c.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(91) err = routes.AccountEditAvatarSubmit(w,req,user) case "/user/edit/avatar/revoke/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(92) err = routes.AccountEditRevokeAvatarSubmit(w,req,user) case "/user/edit/username/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(93) err = routes.AccountEditUsernameSubmit(w,req,user) case "/user/edit/mfa/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(94) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditMFA(w,req,user,head) case "/user/edit/mfa/setup/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(95) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditMFASetup(w,req,user,head) case "/user/edit/mfa/setup/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(96) err = routes.AccountEditMFASetupSubmit(w,req,user) case "/user/edit/mfa/disable/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(97) err = routes.AccountEditMFADisableSubmit(w,req,user) case "/user/edit/email/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(98) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountEditEmail(w,req,user,head) case "/user/edit/token/": counters.RouteViewCounter.Bump(99) err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData) case "/user/edit/logins/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(100) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountLogins(w,req,user,head) case "/user/levels/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(101) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.LevelList(w,req,user,head) default: req.URL.Path += extraData counters.RouteViewCounter.Bump(102) head, err := c.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 = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(103) err = routes.BanUserSubmit(w,req,user,extraData) case "/users/unban/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(104) err = routes.UnbanUser(w,req,user,extraData) case "/users/activate/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(105) err = routes.ActivateUser(w,req,user,extraData) case "/users/ips/": err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(106) head, err := c.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 = c.MemberOnly(w,req,user) if err != nil { return err } err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { return err } err = c.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(107) err = routes.CreateTopicSubmit(w,req,user) case "/topic/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(108) err = routes.EditTopicSubmit(w,req,user,extraData) case "/topic/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } req.URL.Path += extraData counters.RouteViewCounter.Bump(109) err = routes.DeleteTopicSubmit(w,req,user) case "/topic/stick/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(110) err = routes.StickTopicSubmit(w,req,user,extraData) case "/topic/unstick/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(111) err = routes.UnstickTopicSubmit(w,req,user,extraData) case "/topic/lock/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } req.URL.Path += extraData counters.RouteViewCounter.Bump(112) err = routes.LockTopicSubmit(w,req,user) case "/topic/unlock/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(113) err = routes.UnlockTopicSubmit(w,req,user,extraData) case "/topic/move/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(114) err = routes.MoveTopicSubmit(w,req,user,extraData) case "/topic/like/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(115) err = routes.LikeTopicSubmit(w,req,user,extraData) case "/topic/attach/add/submit/": err = c.MemberOnly(w,req,user) if err != nil { return err } err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { return err } err = c.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(116) err = routes.AddAttachToTopicSubmit(w,req,user,extraData) case "/topic/attach/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(117) err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData) default: counters.RouteViewCounter.Bump(118) head, err := c.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 = c.MemberOnly(w,req,user) if err != nil { return err } err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { return err } err = c.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(119) err = routes.CreateReplySubmit(w,req,user) case "/reply/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(120) err = routes.ReplyEditSubmit(w,req,user,extraData) case "/reply/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(121) err = routes.ReplyDeleteSubmit(w,req,user,extraData) case "/reply/like/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(122) err = routes.ReplyLikeSubmit(w,req,user,extraData) case "/reply/attach/add/submit/": err = c.MemberOnly(w,req,user) if err != nil { return err } err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize)) if err != nil { return err } err = c.NoUploadSessionMismatch(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(123) err = routes.AddAttachToReplySubmit(w,req,user,extraData) case "/reply/attach/remove/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(124) err = routes.RemoveAttachFromReplySubmit(w,req,user,extraData) } case "/profile": switch(req.URL.Path) { case "/profile/reply/create/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(125) err = routes.ProfileReplyCreateSubmit(w,req,user) case "/profile/reply/edit/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(126) err = routes.ProfileReplyEditSubmit(w,req,user,extraData) case "/profile/reply/delete/submit/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(127) err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData) } case "/poll": switch(req.URL.Path) { case "/poll/vote/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(128) err = routes.PollVote(w,req,user,extraData) case "/poll/results/": counters.RouteViewCounter.Bump(129) err = routes.PollResults(w,req,user,extraData) } case "/accounts": switch(req.URL.Path) { case "/accounts/login/": counters.RouteViewCounter.Bump(130) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountLogin(w,req,user,head) case "/accounts/create/": counters.RouteViewCounter.Bump(131) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountRegister(w,req,user,head) case "/accounts/logout/": err = c.NoSessionMismatch(w,req,user) if err != nil { return err } err = c.MemberOnly(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(132) err = routes.AccountLogout(w,req,user) case "/accounts/login/submit/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(133) err = routes.AccountLoginSubmit(w,req,user) case "/accounts/mfa_verify/": counters.RouteViewCounter.Bump(134) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountLoginMFAVerify(w,req,user,head) case "/accounts/mfa_verify/submit/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(135) err = routes.AccountLoginMFAVerifySubmit(w,req,user) case "/accounts/create/submit/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(136) err = routes.AccountRegisterSubmit(w,req,user) case "/accounts/password-reset/": counters.RouteViewCounter.Bump(137) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountPasswordReset(w,req,user,head) case "/accounts/password-reset/submit/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(138) err = routes.AccountPasswordResetSubmit(w,req,user) case "/accounts/password-reset/token/": counters.RouteViewCounter.Bump(139) head, err := c.UserCheck(w,req,&user) if err != nil { return err } err = routes.AccountPasswordResetToken(w,req,user,head) case "/accounts/password-reset/token/submit/": err = c.ParseForm(w,req,user) if err != nil { return err } counters.RouteViewCounter.Bump(140) err = routes.AccountPasswordResetTokenSubmit(w,req,user) } /*case "/sitemaps": // TODO: Count these views req.URL.Path += extraData err = sitemapSwitch(w,req)*/ case "/uploads": if extraData == "" { return c.NotFound(w,req,nil) } gzw, ok := w.(c.GzipResponseWriter) if ok { w = gzw.ResponseWriter h := w.Header() h.Del("Content-Type") h.Del("Content-Encoding") } counters.RouteViewCounter.Bump(142) 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(144) return routes.RobotsTxt(w,req) case "favicon.ico": gzw, ok := w.(c.GzipResponseWriter) if ok { w = gzw.ResponseWriter h := w.Header() h.Del("Content-Type") h.Del("Content-Encoding") } req.URL.Path = "/static/favicon.ico" routes.StaticFile(w,req) return nil case "opensearch.xml": counters.RouteViewCounter.Bump(146) return routes.OpenSearchXml(w,req) /*case "sitemap.xml": counters.RouteViewCounter.Bump(145) return routes.SitemapXml(w,req)*/ } return c.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(141) // 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(147) return c.NotFound(w,req,nil) } return err }