From 583c3b16bdcfc4c9e34e03e2557202064b5df84a Mon Sep 17 00:00:00 2001 From: Azareal Date: Sun, 10 Sep 2017 18:05:13 +0100 Subject: [PATCH] We don't want middleware in user.go --- routes_common.go | 295 ++++++++++++++++++++++++++++++++++++++++++++++- user.go | 293 ---------------------------------------------- 2 files changed, 294 insertions(+), 294 deletions(-) diff --git a/routes_common.go b/routes_common.go index 99443f65..b15f1b4e 100644 --- a/routes_common.go +++ b/routes_common.go @@ -1,3 +1,296 @@ package main -// TODO: Move PreRoute and it's friends here in the next commit, I'm avoiding doing it in this one as I don't want the diffs to be lost +import ( + "html" + "html/template" + "net" + "net/http" + "strings" +) + +// nolint +var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = preRoute + +// TODO: Are these even session checks anymore? We might need to rethink these names +// nolint We need these types so people can tell what they are without scrolling to the bottom of the file +var PanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderVars, PanelStats, bool) = _panel_session_check +var SimplePanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderLite, bool) = _simple_panel_session_check +var SimpleForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, success bool) = _simple_forum_session_check +var ForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, success bool) = _forum_session_check +var SimpleSessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) = _simple_session_check +var SessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) = _session_check + +// TODO: Support for left sidebars and sidebars on both sides +// http.Request is for context.Context middleware. Mostly for plugin_socialgroups right now +func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) { + if vhooks["intercept_build_widgets"] != nil { + if runVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) { + return + } + } + + //log.Print("themes[headerVars.ThemeName].Sidebars",themes[headerVars.ThemeName].Sidebars) + if themes[headerVars.ThemeName].Sidebars == "right" { + if len(docks.RightSidebar) != 0 { + var sbody string + for _, widget := range docks.RightSidebar { + if widget.Enabled { + if widget.Location == "global" || widget.Location == zone { + sbody += widget.Body + } + } + } + headerVars.Widgets.RightSidebar = template.HTML(sbody) + } + } +} + +func _simple_forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, success bool) { + if !fstore.Exists(fid) { + PreError("The target forum doesn't exist.", w, r) + return nil, false + } + success = true + + // Is there a better way of doing the skip AND the success flag on this hook like multiple returns? + if vhooks["simple_forum_check_pre_perms"] != nil { + if runVhook("simple_forum_check_pre_perms", w, r, user, &fid, &success, &headerLite).(bool) { + return headerLite, success + } + } + + fperms := groups[user.Group].Forums[fid] + if fperms.Overrides && !user.IsSuperAdmin { + user.Perms.ViewTopic = fperms.ViewTopic + user.Perms.LikeItem = fperms.LikeItem + user.Perms.CreateTopic = fperms.CreateTopic + user.Perms.EditTopic = fperms.EditTopic + user.Perms.DeleteTopic = fperms.DeleteTopic + user.Perms.CreateReply = fperms.CreateReply + user.Perms.EditReply = fperms.EditReply + user.Perms.DeleteReply = fperms.DeleteReply + user.Perms.PinTopic = fperms.PinTopic + user.Perms.CloseTopic = fperms.CloseTopic + + if len(fperms.ExtData) != 0 { + for name, perm := range fperms.ExtData { + user.PluginPerms[name] = perm + } + } + } + return headerLite, true +} + +func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, success bool) { + headerVars, success = SessionCheck(w, r, user) + if !fstore.Exists(fid) { + NotFound(w, r) + return headerVars, false + } + + if vhooks["forum_check_pre_perms"] != nil { + if runVhook("forum_check_pre_perms", w, r, user, &fid, &success, &headerVars).(bool) { + return headerVars, success + } + } + + fperms := groups[user.Group].Forums[fid] + //log.Printf("user.Perms: %+v\n", user.Perms) + //log.Printf("fperms: %+v\n", fperms) + if fperms.Overrides && !user.IsSuperAdmin { + user.Perms.ViewTopic = fperms.ViewTopic + user.Perms.LikeItem = fperms.LikeItem + user.Perms.CreateTopic = fperms.CreateTopic + user.Perms.EditTopic = fperms.EditTopic + user.Perms.DeleteTopic = fperms.DeleteTopic + user.Perms.CreateReply = fperms.CreateReply + user.Perms.EditReply = fperms.EditReply + user.Perms.DeleteReply = fperms.DeleteReply + user.Perms.PinTopic = fperms.PinTopic + user.Perms.CloseTopic = fperms.CloseTopic + + if len(fperms.ExtData) != 0 { + for name, perm := range fperms.ExtData { + user.PluginPerms[name] = perm + } + } + } + return headerVars, success +} + +// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with +// TODO: Do a panel specific theme? +func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, success bool) { + var themeName = defaultThemeBox.Load().(string) + + cookie, err := r.Cookie("current_theme") + if err == nil { + cookie := html.EscapeString(cookie.Value) + theme, ok := themes[cookie] + if ok && !theme.HideFromThemes { + themeName = cookie + } + } + + headerVars = &HeaderVars{ + Site: site, + Settings: settingBox.Load().(SettingBox), + Themes: themes, + ThemeName: themeName, + } + // TODO: We should probably initialise headerVars.ExtData + + if !user.IsSuperMod { + NoPermissions(w, r, *user) + return headerVars, stats, false + } + + headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css") + if len(themes[headerVars.ThemeName].Resources) != 0 { + rlist := themes[headerVars.ThemeName].Resources + for _, resource := range rlist { + if resource.Location == "global" || resource.Location == "panel" { + halves := strings.Split(resource.Name, ".") + if len(halves) != 2 { + continue + } + if halves[1] == "css" { + headerVars.Stylesheets = append(headerVars.Stylesheets, resource.Name) + } else if halves[1] == "js" { + headerVars.Scripts = append(headerVars.Scripts, resource.Name) + } + } + } + } + + err = group_count_stmt.QueryRow().Scan(&stats.Groups) + if err != nil { + InternalError(err, w) + return headerVars, stats, false + } + + stats.Users = users.GetGlobalCount() + stats.Forums = fstore.GetGlobalCount() // TODO: Stop it from showing the blanked forums + stats.Settings = len(headerVars.Settings) + stats.WordFilters = len(wordFilterBox.Load().(WordFilterBox)) + stats.Themes = len(themes) + stats.Reports = 0 // TODO: Do the report count. Only show open threads? + + pusher, ok := w.(http.Pusher) + if ok { + pusher.Push("/static/"+headerVars.ThemeName+"/main.css", nil) + pusher.Push("/static/"+headerVars.ThemeName+"/panel.css", nil) + pusher.Push("/static/global.js", nil) + pusher.Push("/static/jquery-3.1.1.min.js", nil) + // TODO: Push the theme CSS files + // TODO: Push the theme scripts + // TODO: Push avatars? + } + + return headerVars, stats, true +} + +func _simple_panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) { + if !user.IsSuperMod { + NoPermissions(w, r, *user) + return headerLite, false + } + headerLite = &HeaderLite{ + Site: site, + Settings: settingBox.Load().(SettingBox), + } + return headerLite, true +} + +// SimpleSessionCheck is back from the grave, yay :D +func _simple_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) { + headerLite = &HeaderLite{ + Site: site, + Settings: settingBox.Load().(SettingBox), + } + return headerLite, true +} + +// TODO: Add the ability for admins to restrict certain themes to certain groups? +func _session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) { + var themeName = defaultThemeBox.Load().(string) + + cookie, err := r.Cookie("current_theme") + if err == nil { + cookie := html.EscapeString(cookie.Value) + theme, ok := themes[cookie] + if ok && !theme.HideFromThemes { + themeName = cookie + } + } + + headerVars = &HeaderVars{ + Site: site, + Settings: settingBox.Load().(SettingBox), + Themes: themes, + ThemeName: themeName, + } + + if user.IsBanned { + headerVars.NoticeList = append(headerVars.NoticeList, "Your account has been suspended. Some of your permissions may have been revoked.") + } + + if len(themes[headerVars.ThemeName].Resources) != 0 { + rlist := themes[headerVars.ThemeName].Resources + for _, resource := range rlist { + if resource.Location == "global" || resource.Location == "frontend" { + halves := strings.Split(resource.Name, ".") + if len(halves) != 2 { + continue + } + if halves[1] == "css" { + headerVars.Stylesheets = append(headerVars.Stylesheets, resource.Name) + } else if halves[1] == "js" { + headerVars.Scripts = append(headerVars.Scripts, resource.Name) + } + } + } + } + + pusher, ok := w.(http.Pusher) + if ok { + pusher.Push("/static/"+headerVars.ThemeName+"/main.css", nil) + pusher.Push("/static/global.js", nil) + pusher.Push("/static/jquery-3.1.1.min.js", nil) + // TODO: Push the theme CSS files + // TODO: Push the theme scripts + // TODO: Push avatars? + } + + return headerVars, true +} + +func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) { + user, halt := auth.SessionCheck(w, r) + if halt { + return *user, false + } + if user == &guestUser { + return *user, true + } + + host, _, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + PreError("Bad IP", w, r) + return *user, false + } + if host != user.LastIP { + _, err = update_last_ip_stmt.Exec(host, user.ID) + if err != nil { + InternalError(err, w) + return *user, false + } + user.LastIP = host + } + + h := w.Header() + h.Set("X-Frame-Options", "deny") + //h.Set("X-XSS-Protection", "1") + // TODO: Set the content policy header + return *user, true +} diff --git a/user.go b/user.go index 33d0ad2f..e1f55e20 100644 --- a/user.go +++ b/user.go @@ -3,12 +3,7 @@ package main import ( //"log" //"fmt" - "html" - "html/template" - "net" - "net/http" "strconv" - "strings" "time" "golang.org/x/crypto/bcrypt" @@ -16,18 +11,6 @@ import ( var guestUser = User{ID: 0, Link: "#", Group: 6, Perms: GuestPerms} -// nolint -var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = preRoute - -// TODO: Are these even session checks anymore? We might need to rethink these names -// nolint We need these types so people can tell what they are without scrolling to the bottom of the file -var PanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderVars, PanelStats, bool) = _panel_session_check -var SimplePanelSessionCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderLite, bool) = _simple_panel_session_check -var SimpleForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, success bool) = _simple_forum_session_check -var ForumSessionCheck func(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, success bool) = _forum_session_check -var SimpleSessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) = _simple_session_check -var SessionCheck func(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) = _session_check - //func(real_password string, password string, salt string) (err error) var CheckPassword = BcryptCheckPassword @@ -69,7 +52,6 @@ type Email struct { Token string } -// duration in seconds func (user *User) Ban(duration time.Duration, issuedBy int) error { return user.ScheduleGroupUpdate(4, issuedBy, duration) } @@ -163,281 +145,6 @@ func SendValidationEmail(username string, email string, token string) bool { return SendEmail(email, subject, msg) } -// TODO: Support for left sidebars and sidebars on both sides -// http.Request is for context.Context middleware. Mostly for plugin_socialgroups right now -func BuildWidgets(zone string, data interface{}, headerVars *HeaderVars, r *http.Request) { - if vhooks["intercept_build_widgets"] != nil { - if runVhook("intercept_build_widgets", zone, data, headerVars, r).(bool) { - return - } - } - - //log.Print("themes[headerVars.ThemeName].Sidebars",themes[headerVars.ThemeName].Sidebars) - if themes[headerVars.ThemeName].Sidebars == "right" { - if len(docks.RightSidebar) != 0 { - var sbody string - for _, widget := range docks.RightSidebar { - if widget.Enabled { - if widget.Location == "global" || widget.Location == zone { - sbody += widget.Body - } - } - } - headerVars.Widgets.RightSidebar = template.HTML(sbody) - } - } -} - -func _simple_forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerLite *HeaderLite, success bool) { - if !fstore.Exists(fid) { - PreError("The target forum doesn't exist.", w, r) - return nil, false - } - success = true - - // Is there a better way of doing the skip AND the success flag on this hook like multiple returns? - if vhooks["simple_forum_check_pre_perms"] != nil { - if runVhook("simple_forum_check_pre_perms", w, r, user, &fid, &success, &headerLite).(bool) { - return headerLite, success - } - } - - fperms := groups[user.Group].Forums[fid] - if fperms.Overrides && !user.IsSuperAdmin { - user.Perms.ViewTopic = fperms.ViewTopic - user.Perms.LikeItem = fperms.LikeItem - user.Perms.CreateTopic = fperms.CreateTopic - user.Perms.EditTopic = fperms.EditTopic - user.Perms.DeleteTopic = fperms.DeleteTopic - user.Perms.CreateReply = fperms.CreateReply - user.Perms.EditReply = fperms.EditReply - user.Perms.DeleteReply = fperms.DeleteReply - user.Perms.PinTopic = fperms.PinTopic - user.Perms.CloseTopic = fperms.CloseTopic - - if len(fperms.ExtData) != 0 { - for name, perm := range fperms.ExtData { - user.PluginPerms[name] = perm - } - } - } - return headerLite, true -} - -func _forum_session_check(w http.ResponseWriter, r *http.Request, user *User, fid int) (headerVars *HeaderVars, success bool) { - headerVars, success = SessionCheck(w, r, user) - if !fstore.Exists(fid) { - NotFound(w, r) - return headerVars, false - } - - if vhooks["forum_check_pre_perms"] != nil { - if runVhook("forum_check_pre_perms", w, r, user, &fid, &success, &headerVars).(bool) { - return headerVars, success - } - } - - fperms := groups[user.Group].Forums[fid] - //log.Printf("user.Perms: %+v\n", user.Perms) - //log.Printf("fperms: %+v\n", fperms) - if fperms.Overrides && !user.IsSuperAdmin { - user.Perms.ViewTopic = fperms.ViewTopic - user.Perms.LikeItem = fperms.LikeItem - user.Perms.CreateTopic = fperms.CreateTopic - user.Perms.EditTopic = fperms.EditTopic - user.Perms.DeleteTopic = fperms.DeleteTopic - user.Perms.CreateReply = fperms.CreateReply - user.Perms.EditReply = fperms.EditReply - user.Perms.DeleteReply = fperms.DeleteReply - user.Perms.PinTopic = fperms.PinTopic - user.Perms.CloseTopic = fperms.CloseTopic - - if len(fperms.ExtData) != 0 { - for name, perm := range fperms.ExtData { - user.PluginPerms[name] = perm - } - } - } - return headerVars, success -} - -// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with -// TODO: Do a panel specific theme? -func _panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, success bool) { - var themeName = defaultThemeBox.Load().(string) - - cookie, err := r.Cookie("current_theme") - if err == nil { - cookie := html.EscapeString(cookie.Value) - theme, ok := themes[cookie] - if ok && !theme.HideFromThemes { - themeName = cookie - } - } - - headerVars = &HeaderVars{ - Site: site, - Settings: settingBox.Load().(SettingBox), - Themes: themes, - ThemeName: themeName, - } - // TODO: We should probably initialise headerVars.ExtData - - if !user.IsSuperMod { - NoPermissions(w, r, *user) - return headerVars, stats, false - } - - headerVars.Stylesheets = append(headerVars.Stylesheets, headerVars.ThemeName+"/panel.css") - if len(themes[headerVars.ThemeName].Resources) != 0 { - rlist := themes[headerVars.ThemeName].Resources - for _, resource := range rlist { - if resource.Location == "global" || resource.Location == "panel" { - halves := strings.Split(resource.Name, ".") - if len(halves) != 2 { - continue - } - if halves[1] == "css" { - headerVars.Stylesheets = append(headerVars.Stylesheets, resource.Name) - } else if halves[1] == "js" { - headerVars.Scripts = append(headerVars.Scripts, resource.Name) - } - } - } - } - - err = group_count_stmt.QueryRow().Scan(&stats.Groups) - if err != nil { - InternalError(err, w) - return headerVars, stats, false - } - - stats.Users = users.GetGlobalCount() - stats.Forums = fstore.GetGlobalCount() // TODO: Stop it from showing the blanked forums - stats.Settings = len(headerVars.Settings) - stats.WordFilters = len(wordFilterBox.Load().(WordFilterBox)) - stats.Themes = len(themes) - stats.Reports = 0 // TODO: Do the report count. Only show open threads? - - pusher, ok := w.(http.Pusher) - if ok { - pusher.Push("/static/"+headerVars.ThemeName+"/main.css", nil) - pusher.Push("/static/"+headerVars.ThemeName+"/panel.css", nil) - pusher.Push("/static/global.js", nil) - pusher.Push("/static/jquery-3.1.1.min.js", nil) - // TODO: Push the theme CSS files - // TODO: Push the theme scripts - // TODO: Push avatars? - } - - return headerVars, stats, true -} - -func _simple_panel_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) { - if !user.IsSuperMod { - NoPermissions(w, r, *user) - return headerLite, false - } - headerLite = &HeaderLite{ - Site: site, - Settings: settingBox.Load().(SettingBox), - } - return headerLite, true -} - -// SimpleSessionCheck is back from the grave, yay :D -func _simple_session_check(w http.ResponseWriter, r *http.Request, user *User) (headerLite *HeaderLite, success bool) { - headerLite = &HeaderLite{ - Site: site, - Settings: settingBox.Load().(SettingBox), - } - return headerLite, true -} - -// TODO: Add the ability for admins to restrict certain themes to certain groups? -func _session_check(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, success bool) { - var themeName = defaultThemeBox.Load().(string) - - cookie, err := r.Cookie("current_theme") - if err == nil { - cookie := html.EscapeString(cookie.Value) - theme, ok := themes[cookie] - if ok && !theme.HideFromThemes { - themeName = cookie - } - } - - headerVars = &HeaderVars{ - Site: site, - Settings: settingBox.Load().(SettingBox), - Themes: themes, - ThemeName: themeName, - } - - if user.IsBanned { - headerVars.NoticeList = append(headerVars.NoticeList, "Your account has been suspended. Some of your permissions may have been revoked.") - } - - if len(themes[headerVars.ThemeName].Resources) != 0 { - rlist := themes[headerVars.ThemeName].Resources - for _, resource := range rlist { - if resource.Location == "global" || resource.Location == "frontend" { - halves := strings.Split(resource.Name, ".") - if len(halves) != 2 { - continue - } - if halves[1] == "css" { - headerVars.Stylesheets = append(headerVars.Stylesheets, resource.Name) - } else if halves[1] == "js" { - headerVars.Scripts = append(headerVars.Scripts, resource.Name) - } - } - } - } - - pusher, ok := w.(http.Pusher) - if ok { - pusher.Push("/static/"+headerVars.ThemeName+"/main.css", nil) - pusher.Push("/static/global.js", nil) - pusher.Push("/static/jquery-3.1.1.min.js", nil) - // TODO: Push the theme CSS files - // TODO: Push the theme scripts - // TODO: Push avatars? - } - - return headerVars, true -} - -func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) { - user, halt := auth.SessionCheck(w, r) - if halt { - return *user, false - } - if user == &guestUser { - return *user, true - } - - host, _, err := net.SplitHostPort(r.RemoteAddr) - if err != nil { - PreError("Bad IP", w, r) - return *user, false - } - if host != user.LastIP { - _, err = update_last_ip_stmt.Exec(host, user.ID) - if err != nil { - InternalError(err, w) - return *user, false - } - user.LastIP = host - } - - h := w.Header() - h.Set("X-Frame-Options", "deny") - //h.Set("X-XSS-Protection", "1") - // TODO: Set the content policy header - return *user, true -} - func wordsToScore(wcount int, topic bool) (score int) { if topic { score = 2