523 lines
12 KiB
Go
523 lines
12 KiB
Go
package common
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"log"
|
|
"sync"
|
|
)
|
|
|
|
// TODO: Refactor the perms system
|
|
|
|
var permUpdateMutex sync.Mutex
|
|
var BlankPerms Perms
|
|
var BlankForumPerms ForumPerms
|
|
var GuestPerms Perms
|
|
var ReadForumPerms ForumPerms
|
|
var ReadReplyForumPerms ForumPerms
|
|
var ReadWriteForumPerms ForumPerms
|
|
var AllPerms Perms
|
|
var AllForumPerms ForumPerms
|
|
var AllPluginPerms = make(map[string]bool)
|
|
|
|
// ? - Can we avoid duplicating the items in this list in a bunch of places?
|
|
|
|
var LocalPermList = []string{
|
|
"ViewTopic",
|
|
"LikeItem",
|
|
"CreateTopic",
|
|
"EditTopic",
|
|
"DeleteTopic",
|
|
"CreateReply",
|
|
"EditReply",
|
|
"DeleteReply",
|
|
"PinTopic",
|
|
"CloseTopic",
|
|
}
|
|
|
|
// ? - Can we avoid duplicating the items in this list in a bunch of places?
|
|
var GlobalPermList = []string{
|
|
"BanUsers",
|
|
"ActivateUsers",
|
|
"EditUser",
|
|
"EditUserEmail",
|
|
"EditUserPassword",
|
|
"EditUserGroup",
|
|
"EditUserGroupSuperMod",
|
|
"EditUserGroupAdmin",
|
|
"EditGroup",
|
|
"EditGroupLocalPerms",
|
|
"EditGroupGlobalPerms",
|
|
"EditGroupSuperMod",
|
|
"EditGroupAdmin",
|
|
"ManageForums",
|
|
"EditSettings",
|
|
"ManageThemes",
|
|
"ManagePlugins",
|
|
"ViewAdminLogs",
|
|
"ViewIPs",
|
|
"UploadFiles",
|
|
}
|
|
|
|
// Permission Structure: ActionComponent[Subcomponent]Flag
|
|
type Perms struct {
|
|
// Global Permissions
|
|
BanUsers bool
|
|
ActivateUsers bool
|
|
EditUser bool
|
|
EditUserEmail bool
|
|
EditUserPassword bool
|
|
EditUserGroup bool
|
|
EditUserGroupSuperMod bool
|
|
EditUserGroupAdmin bool
|
|
EditGroup bool
|
|
EditGroupLocalPerms bool
|
|
EditGroupGlobalPerms bool
|
|
EditGroupSuperMod bool
|
|
EditGroupAdmin bool
|
|
ManageForums bool // This could be local, albeit limited for per-forum managers?
|
|
EditSettings bool
|
|
ManageThemes bool
|
|
ManagePlugins bool
|
|
ViewAdminLogs bool
|
|
ViewIPs bool
|
|
|
|
// Global non-staff permissions
|
|
UploadFiles bool
|
|
// TODO: Add a permission for enabling avatars
|
|
|
|
// Forum permissions
|
|
ViewTopic bool
|
|
//ViewOwnTopic bool
|
|
LikeItem bool
|
|
CreateTopic bool
|
|
EditTopic bool
|
|
DeleteTopic bool
|
|
CreateReply bool
|
|
//CreateReplyToOwn bool
|
|
EditReply bool
|
|
//EditOwnReply bool
|
|
DeleteReply bool
|
|
PinTopic bool
|
|
CloseTopic bool
|
|
//CloseOwnTopic bool
|
|
|
|
//ExtData map[string]bool
|
|
}
|
|
|
|
/* Inherit from group permissions for ones we don't have */
|
|
type ForumPerms struct {
|
|
ViewTopic bool
|
|
//ViewOwnTopic bool
|
|
LikeItem bool
|
|
CreateTopic bool
|
|
EditTopic bool
|
|
DeleteTopic bool
|
|
CreateReply bool
|
|
//CreateReplyToOwn bool
|
|
EditReply bool
|
|
//EditOwnReply bool
|
|
DeleteReply bool
|
|
PinTopic bool
|
|
CloseTopic bool
|
|
//CloseOwnTopic bool
|
|
|
|
Overrides bool
|
|
ExtData map[string]bool
|
|
}
|
|
|
|
func init() {
|
|
BlankPerms = Perms{
|
|
//ExtData: make(map[string]bool),
|
|
}
|
|
|
|
BlankForumPerms = ForumPerms{
|
|
ExtData: make(map[string]bool),
|
|
}
|
|
|
|
GuestPerms = Perms{
|
|
ViewTopic: true,
|
|
//ExtData: make(map[string]bool),
|
|
}
|
|
|
|
AllPerms = Perms{
|
|
BanUsers: true,
|
|
ActivateUsers: true,
|
|
EditUser: true,
|
|
EditUserEmail: true,
|
|
EditUserPassword: true,
|
|
EditUserGroup: true,
|
|
EditUserGroupSuperMod: true,
|
|
EditUserGroupAdmin: true,
|
|
EditGroup: true,
|
|
EditGroupLocalPerms: true,
|
|
EditGroupGlobalPerms: true,
|
|
EditGroupSuperMod: true,
|
|
EditGroupAdmin: true,
|
|
ManageForums: true,
|
|
EditSettings: true,
|
|
ManageThemes: true,
|
|
ManagePlugins: true,
|
|
ViewAdminLogs: true,
|
|
ViewIPs: true,
|
|
|
|
UploadFiles: true,
|
|
|
|
ViewTopic: true,
|
|
LikeItem: true,
|
|
CreateTopic: true,
|
|
EditTopic: true,
|
|
DeleteTopic: true,
|
|
CreateReply: true,
|
|
EditReply: true,
|
|
DeleteReply: true,
|
|
PinTopic: true,
|
|
CloseTopic: true,
|
|
|
|
//ExtData: make(map[string]bool),
|
|
}
|
|
|
|
AllForumPerms = ForumPerms{
|
|
ViewTopic: true,
|
|
LikeItem: true,
|
|
CreateTopic: true,
|
|
EditTopic: true,
|
|
DeleteTopic: true,
|
|
CreateReply: true,
|
|
EditReply: true,
|
|
DeleteReply: true,
|
|
PinTopic: true,
|
|
CloseTopic: true,
|
|
|
|
Overrides: true,
|
|
ExtData: make(map[string]bool),
|
|
}
|
|
|
|
ReadWriteForumPerms = ForumPerms{
|
|
ViewTopic: true,
|
|
LikeItem: true,
|
|
CreateTopic: true,
|
|
CreateReply: true,
|
|
Overrides: true,
|
|
ExtData: make(map[string]bool),
|
|
}
|
|
|
|
ReadReplyForumPerms = ForumPerms{
|
|
ViewTopic: true,
|
|
LikeItem: true,
|
|
CreateReply: true,
|
|
Overrides: true,
|
|
ExtData: make(map[string]bool),
|
|
}
|
|
|
|
ReadForumPerms = ForumPerms{
|
|
ViewTopic: true,
|
|
Overrides: true,
|
|
ExtData: make(map[string]bool),
|
|
}
|
|
|
|
guestUser.Perms = GuestPerms
|
|
|
|
if dev.DebugMode {
|
|
log.Printf("Guest Perms: %+v\n", GuestPerms)
|
|
log.Printf("All Perms: %+v\n", AllPerms)
|
|
}
|
|
}
|
|
|
|
func presetToPermmap(preset string) (out map[string]ForumPerms) {
|
|
out = make(map[string]ForumPerms)
|
|
switch preset {
|
|
case "all":
|
|
out["guests"] = ReadForumPerms
|
|
out["members"] = ReadWriteForumPerms
|
|
out["staff"] = AllForumPerms
|
|
out["admins"] = AllForumPerms
|
|
case "announce":
|
|
out["guests"] = ReadForumPerms
|
|
out["members"] = ReadReplyForumPerms
|
|
out["staff"] = AllForumPerms
|
|
out["admins"] = AllForumPerms
|
|
case "members":
|
|
out["guests"] = BlankForumPerms
|
|
out["members"] = ReadWriteForumPerms
|
|
out["staff"] = AllForumPerms
|
|
out["admins"] = AllForumPerms
|
|
case "staff":
|
|
out["guests"] = BlankForumPerms
|
|
out["members"] = BlankForumPerms
|
|
out["staff"] = ReadWriteForumPerms
|
|
out["admins"] = AllForumPerms
|
|
case "admins":
|
|
out["guests"] = BlankForumPerms
|
|
out["members"] = BlankForumPerms
|
|
out["staff"] = BlankForumPerms
|
|
out["admins"] = AllForumPerms
|
|
case "archive":
|
|
out["guests"] = ReadForumPerms
|
|
out["members"] = ReadForumPerms
|
|
out["staff"] = ReadForumPerms
|
|
out["admins"] = ReadForumPerms //CurateForumPerms. Delete / Edit but no create?
|
|
default:
|
|
out["guests"] = BlankForumPerms
|
|
out["members"] = BlankForumPerms
|
|
out["staff"] = BlankForumPerms
|
|
out["admins"] = BlankForumPerms
|
|
}
|
|
return out
|
|
}
|
|
|
|
func permmapToQuery(permmap map[string]ForumPerms, fid int) error {
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
deleteForumPermsByForumTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "fid = ?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = deleteForumPermsByForumTx.Exec(fid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
perms, err := json.Marshal(permmap["admins"])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
addForumPermsToForumAdminsTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
|
|
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
|
|
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 1", "", ""},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = addForumPermsToForumAdminsTx.Exec(fid, "", perms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
perms, err = json.Marshal(permmap["staff"])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
addForumPermsToForumStaffTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
|
|
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
|
|
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 1", "", ""},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = addForumPermsToForumStaffTx.Exec(fid, "", perms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
perms, err = json.Marshal(permmap["members"])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
addForumPermsToForumMembersTx, err := qgen.Builder.SimpleInsertSelectTx(tx,
|
|
qgen.DB_Insert{"forums_permissions", "gid, fid, preset, permissions", ""},
|
|
qgen.DB_Select{"users_groups", "gid, ? AS fid, ? AS preset, ? AS permissions", "is_admin = 0 AND is_mod = 0 AND is_banned = 0", "", ""},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = addForumPermsToForumMembersTx.Exec(fid, "", perms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 6 is the ID of the Not Loggedin Group
|
|
// TODO: Use a shared variable rather than a literal for the group ID
|
|
err = replaceForumPermsForGroupTx(tx, 6, map[int]string{fid: ""}, map[int]ForumPerms{fid: permmap["guests"]})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
permUpdateMutex.Lock()
|
|
defer permUpdateMutex.Unlock()
|
|
return fpstore.Reload(fid)
|
|
}
|
|
|
|
func replaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]ForumPerms) error {
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
err = replaceForumPermsForGroupTx(tx, gid, presetSet, permSets)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return tx.Commit()
|
|
}
|
|
|
|
func replaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string, permSets map[int]ForumPerms) error {
|
|
deleteForumPermsForGroupTx, err := qgen.Builder.SimpleDeleteTx(tx, "forums_permissions", "gid = ? AND fid = ?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
addForumPermsToGroupTx, err := qgen.Builder.SimpleInsertTx(tx, "forums_permissions", "gid, fid, preset, permissions", "?,?,?,?")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for fid, permSet := range permSets {
|
|
permstr, err := json.Marshal(permSet)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = deleteForumPermsForGroupTx.Exec(gid, fid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = addForumPermsToGroupTx.Exec(gid, fid, presetSets[fid], string(permstr))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// TODO: Refactor this and write tests for it
|
|
func forumPermsToGroupForumPreset(fperms ForumPerms) string {
|
|
if !fperms.Overrides {
|
|
return "default"
|
|
}
|
|
if !fperms.ViewTopic {
|
|
return "no_access"
|
|
}
|
|
var canPost = (fperms.LikeItem && fperms.CreateTopic && fperms.CreateReply)
|
|
var canModerate = (canPost && fperms.EditTopic && fperms.DeleteTopic && fperms.EditReply && fperms.DeleteReply && fperms.PinTopic && fperms.CloseTopic)
|
|
if canModerate {
|
|
return "can_moderate"
|
|
}
|
|
if fperms.EditTopic || fperms.DeleteTopic || fperms.EditReply || fperms.DeleteReply || fperms.PinTopic || fperms.CloseTopic {
|
|
if !canPost {
|
|
return "custom"
|
|
}
|
|
return "quasi_mod"
|
|
}
|
|
|
|
if canPost {
|
|
return "can_post"
|
|
}
|
|
if fperms.ViewTopic && !fperms.LikeItem && !fperms.CreateTopic && !fperms.CreateReply {
|
|
return "read_only"
|
|
}
|
|
return "custom"
|
|
}
|
|
|
|
func groupForumPresetToForumPerms(preset string) (fperms ForumPerms, changed bool) {
|
|
switch preset {
|
|
case "read_only":
|
|
return ReadForumPerms, true
|
|
case "can_post":
|
|
return ReadWriteForumPerms, true
|
|
case "can_moderate":
|
|
return AllForumPerms, true
|
|
case "no_access":
|
|
return ForumPerms{Overrides: true, ExtData: make(map[string]bool)}, true
|
|
case "default":
|
|
return BlankForumPerms, true
|
|
//case "custom": return fperms, false
|
|
}
|
|
return fperms, false
|
|
}
|
|
|
|
func stripInvalidGroupForumPreset(preset string) string {
|
|
switch preset {
|
|
case "read_only", "can_post", "can_moderate", "no_access", "default", "custom":
|
|
return preset
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func stripInvalidPreset(preset string) string {
|
|
switch preset {
|
|
case "all", "announce", "members", "staff", "admins", "archive", "custom":
|
|
return preset
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// TODO: Move this into the phrase system?
|
|
func presetToLang(preset string) string {
|
|
phrases := GetAllPermPresets()
|
|
phrase, ok := phrases[preset]
|
|
if !ok {
|
|
phrase = phrases["unknown"]
|
|
}
|
|
return phrase
|
|
}
|
|
|
|
// TODO: Is this racey?
|
|
func rebuildGroupPermissions(gid int) error {
|
|
var permstr []byte
|
|
log.Print("Reloading a group")
|
|
err := db.QueryRow("select permissions from users_groups where gid = ?", gid).Scan(&permstr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tmpPerms := Perms{
|
|
//ExtData: make(map[string]bool),
|
|
}
|
|
err = json.Unmarshal(permstr, &tmpPerms)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
group, err := gstore.Get(gid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
group.Perms = tmpPerms
|
|
return nil
|
|
}
|
|
|
|
func overridePerms(perms *Perms, status bool) {
|
|
if status {
|
|
*perms = AllPerms
|
|
} else {
|
|
*perms = BlankPerms
|
|
}
|
|
}
|
|
|
|
// TODO: We need a better way of overriding forum perms rather than setting them one by one
|
|
func overrideForumPerms(perms *Perms, status bool) {
|
|
perms.ViewTopic = status
|
|
perms.LikeItem = status
|
|
perms.CreateTopic = status
|
|
perms.EditTopic = status
|
|
perms.DeleteTopic = status
|
|
perms.CreateReply = status
|
|
perms.EditReply = status
|
|
perms.DeleteReply = status
|
|
perms.PinTopic = status
|
|
perms.CloseTopic = status
|
|
}
|
|
|
|
func registerPluginPerm(name string) {
|
|
AllPluginPerms[name] = true
|
|
}
|
|
|
|
func deregisterPluginPerm(name string) {
|
|
delete(AllPluginPerms, name)
|
|
}
|