· 7 years ago · Feb 15, 2019, 02:28 PM
1--Immunity
2cvars.AddChangeCallback("_FAdmin_immunity", function(Cvar, Previous, New)
3 FAdmin.SetGlobalSetting("Immunity", (tonumber(New) == 1 and true) or false)
4 FAdmin.SaveSetting("_FAdmin_immunity", tonumber(New))
5end)
6
7hook.Add("DatabaseInitialized", "InitializeFAdminGroups", function()
8 MySQLite.query("CREATE TABLE IF NOT EXISTS FADMIN_GROUPS(NAME VARCHAR(40) NOT NULL PRIMARY KEY, ADMIN_ACCESS INTEGER NOT NULL);")
9 MySQLite.query("CREATE TABLE IF NOT EXISTS FAdmin_PlayerGroup(steamid VARCHAR(40) NOT NULL, groupname VARCHAR(40) NOT NULL, PRIMARY KEY(steamid));")
10 MySQLite.query("CREATE TABLE IF NOT EXISTS FAdmin_Immunity(groupname VARCHAR(40) NOT NULL, immunity INTEGER NOT NULL, PRIMARY KEY(groupname));")
11 MySQLite.query("CREATE TABLE IF NOT EXISTS FAdmin_CAMIPrivileges(privname VARCHAR(255) NOT NULL PRIMARY KEY);")
12 MySQLite.query([[CREATE TABLE IF NOT EXISTS FADMIN_PRIVILEGES(
13 NAME VARCHAR(40),
14 PRIVILEGE VARCHAR(100),
15 PRIMARY KEY(NAME, PRIVILEGE),
16 FOREIGN KEY(NAME) REFERENCES FADMIN_GROUPS(NAME)
17 ON UPDATE CASCADE
18 ON DELETE CASCADE
19 );]], function()
20
21 -- Remove SetAccess workaround
22 MySQLite.query([[DELETE FROM FADMIN_PRIVILEGES WHERE NAME = "user" AND PRIVILEGE = "SetAccess";]])
23
24 MySQLite.query("SELECT g.NAME, g.ADMIN_ACCESS, p.PRIVILEGE, i.immunity FROM FADMIN_GROUPS g LEFT OUTER JOIN FADMIN_PRIVILEGES p ON g.NAME = p.NAME LEFT OUTER JOIN FAdmin_Immunity i ON g.NAME = i.groupname;", function(data)
25 if not data then return end
26
27 for _, v in pairs(data) do
28 FAdmin.Access.Groups[v.NAME] = FAdmin.Access.Groups[v.NAME] or
29 {ADMIN = tonumber(v.ADMIN_ACCESS), PRIVS = {}}
30
31 if v.PRIVILEGE and v.PRIVILEGE ~= "NULL" then
32 FAdmin.Access.Groups[v.NAME].PRIVS[v.PRIVILEGE] = true
33 end
34
35 if v.immunity and v.immunity ~= "NULL" then
36 FAdmin.Access.Groups[v.NAME].immunity = tonumber(v.immunity)
37 end
38
39 if CAMI.GetUsergroup(v.NAME) then continue end
40
41 CAMI.RegisterUsergroup({
42 Name = v.NAME,
43 Inherits = FAdmin.Access.ADMIN[v.ADMIN_ACCESS]
44 }, "FAdmin")
45 end
46
47 -- Send groups to early joiners and listen server hosts
48 for _, v in ipairs(player.GetAll()) do
49 FAdmin.Access.SendGroups(v)
50 end
51
52 -- See if there are any CAMI usergroups that FAdmin doesn't know about yet.
53 -- FAdmin doesn't start listening immediately because the database might not have initialised.
54 -- Besides, other admin mods might add usergroups before FAdmin's Lua files are even run
55 for _, v in pairs(CAMI.GetUsergroups()) do
56 if FAdmin.Access.Groups[v.Name] then continue end
57
58 FAdmin.Access.OnUsergroupRegistered(v)
59 end
60
61 -- Start listening for CAMI usergroup registrations.
62 hook.Add("CAMI.OnUsergroupRegistered", "FAdmin", FAdmin.Access.OnUsergroupRegistered)
63 hook.Add("CAMI.OnUsergroupUnregistered", "FAdmin", FAdmin.Access.OnUsergroupUnregistered)
64
65 FAdmin.Access.RegisterCAMIPrivileges()
66 end)
67
68 local function createGroups(privs)
69 FAdmin.Access.AddGroup("superadmin", 2, privs.superadmin, 100)
70 FAdmin.Access.AddGroup("admin", 1, privs.admin, 50)
71 FAdmin.Access.AddGroup("user", 0, privs.user, 10)
72 FAdmin.Access.AddGroup("noaccess", 0, privs.noaccess, 0)
73 end
74
75 MySQLite.query("SELECT DISTINCT PRIVILEGE FROM FADMIN_PRIVILEGES;", function(privTbl)
76 local privs = {}
77 local hasPrivs = {"noaccess", "user", "admin", "superadmin"}
78
79 -- No privileges registered to anyone. Reset everything
80 if not privTbl or #privTbl == 0 then
81 for priv, access in pairs(FAdmin.Access.Privileges) do
82 for i = access + 1, #hasPrivs, 1 do
83 privs[hasPrivs[i]] = privs[hasPrivs[i]] or {}
84 privs[hasPrivs[i]][priv] = true
85 end
86 end
87
88 createGroups(privs)
89
90 return
91 end
92
93 -- Check for newly created privileges and assign them to the default usergroups
94 -- No privilege can be revoke from every group
95 local privSet = {}
96 for _, priv in ipairs(privTbl) do
97 privSet[priv.PRIVILEGE] = true
98 end
99
100 for priv, access in pairs(FAdmin.Access.Privileges) do
101 if privSet[priv] then continue end
102
103 for i = access + 1, #hasPrivs do
104 MySQLite.query(("REPLACE INTO FADMIN_PRIVILEGES VALUES(%s, %s);"):format(MySQLite.SQLStr(hasPrivs[i]), MySQLite.SQLStr(priv)))
105 end
106 end
107
108 createGroups(privs)
109 end)
110 end)
111end)
112
113-- Assign a privilege to its respective usergroups when they are seen for the first time
114function FAdmin.Access.RegisterCAMIPrivilege(priv)
115 -- Privileges haven't been loaded yet or has already been seen
116 if not FAdmin.CAMIPrivs or FAdmin.CAMIPrivs[priv.Name] then return end
117
118 FAdmin.CAMIPrivs[priv.Name] = true
119
120 for groupName, groupdata in pairs(FAdmin.Access.Groups) do
121 if FAdmin.Access.Privileges[priv.Name] - 1 > groupdata.ADMIN then continue end
122 groupdata.PRIVS[priv.Name] = true
123
124 MySQLite.query(string.format([[REPLACE INTO FADMIN_PRIVILEGES VALUES(%s, %s);]], MySQLite.SQLStr(groupName), MySQLite.SQLStr(priv.Name)))
125 end
126
127 MySQLite.query(string.format([[REPLACE INTO FAdmin_CAMIPrivileges VALUES(%s);]], MySQLite.SQLStr(priv.Name)))
128end
129
130-- Assign privileges to their respective usergroups when they are seen for the first time
131function FAdmin.Access.RegisterCAMIPrivileges()
132 MySQLite.query([[SELECT privname FROM FAdmin_CAMIPrivileges]], function(data)
133 FAdmin.CAMIPrivs = {}
134
135 for _, row in ipairs(data or {}) do
136 FAdmin.CAMIPrivs[row.privname] = true
137 end
138
139
140 for privName, _ in pairs(CAMI.GetPrivileges()) do
141 if FAdmin.CAMIPrivs[privName] then continue end
142 FAdmin.CAMIPrivs[privName] = true
143
144 for groupName, groupdata in pairs(FAdmin.Access.Groups) do
145 if FAdmin.Access.Privileges[privName] - 1 > groupdata.ADMIN then continue end
146 groupdata.PRIVS[privName] = true
147
148 MySQLite.query(string.format([[REPLACE INTO FADMIN_PRIVILEGES VALUES(%s, %s);]], MySQLite.SQLStr(groupName), MySQLite.SQLStr(privName)))
149 end
150
151 MySQLite.query(string.format([[REPLACE INTO FAdmin_CAMIPrivileges VALUES(%s);]], MySQLite.SQLStr(privName)))
152 end
153 end)
154end
155
156function FAdmin.Access.PlayerSetGroup(ply, group)
157 if not FAdmin.Access.Groups[group] then return end
158 ply = isstring(ply) and FAdmin.FindPlayer(ply) and FAdmin.FindPlayer(ply)[1] or ply
159
160 if type(ply) ~= "string" and IsValid(ply) then
161 ply:SetUserGroup(group)
162 end
163end
164
165hook.Remove("PlayerInitialSpawn", "PlayerAuthSpawn") -- Remove Garry's usergroup setter.
166
167-- Update the database only when an end users indicates that a player's usergroup is to be changed.
168hook.Add("CAMI.PlayerUsergroupChanged", "FAdmin", function(ply, old, new, source)
169 MySQLite.query("REPLACE INTO FAdmin_PlayerGroup VALUES(" .. MySQLite.SQLStr(ply:SteamID()) .. ", " .. MySQLite.SQLStr(new) .. ");")
170end)
171
172hook.Add("CAMI.SteamIDUsergroupChanged", "FAdmin", function(steamId, old, new, source)
173 MySQLite.query("REPLACE INTO FAdmin_PlayerGroup VALUES(" .. MySQLite.SQLStr(steamId) .. ", " .. MySQLite.SQLStr(new) .. ");")
174end)
175
176function FAdmin.Access.SetRoot(ply, cmd, args) -- FAdmin setroot player. Sets the player to superadmin
177 if not FAdmin.Access.PlayerHasPrivilege(ply, "SetAccess") then
178 FAdmin.Messages.SendMessage(ply, 5, "No access!")
179 FAdmin.Messages.SendMessage(ply, 5, "Please use RCon to set yourself to superadmin if you are the owner of the server")
180 return false
181 end
182
183 local group = FAdmin.Access.Groups["superadmin"]
184 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
185
186 -- Setting a group with a higher rank than one's own
187 if (not plyGroup or group.immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
188 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to assign anyone a usergroup with a higher rank than your own")
189 FAdmin.Messages.SendMessage(ply, 5, "Please use RCon to set yourself to superadmin if you are the owner of the server")
190 return false
191 end
192
193 local targets = FAdmin.FindPlayer(args[1])
194 if not targets or #targets == 1 and not IsValid(targets[1]) then
195 FAdmin.Messages.SendMessage(ply, 1, "Player not found")
196 return false
197 end
198
199 for _, target in pairs(targets) do
200 if not IsValid(target) then continue end
201
202 FAdmin.Access.PlayerSetGroup(target, "superadmin")
203
204 -- An end user changed the usergroup. Register with CAMI
205 CAMI.SignalUserGroupChanged(target, target:GetUserGroup(), "superadmin", "FAdmin")
206
207 FAdmin.Messages.SendMessage(ply, 2, "User set to superadmin!")
208 end
209
210 FAdmin.Messages.FireNotification("setaccess", ply, targets, {"superadmin"})
211 return true, targets, "superadmin"
212end
213
214-- AddGroup <Groupname> <Adminstatus> <Privileges>
215local function AddGroup(ply, cmd, args)
216 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManageGroups") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
217 local admin = tonumber(args[2])
218 if not args[1] or not admin then FAdmin.Messages.SendMessage(ply, 5, "Incorrect arguments!") return false end
219 local privs = {}
220
221 for priv, am in SortedPairs(FAdmin.Access.Privileges) do
222 -- The user cannot create groups with privileges they don't have
223 if not FAdmin.Access.PlayerHasPrivilege(ply, priv) then continue end
224 if am <= admin + 1 then privs[priv] = true end
225 end
226
227 local immunity = FAdmin.Access.Groups[FAdmin.Access.ADMIN[admin + 1]].immunity
228
229 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
230
231 if (not plyGroup or immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
232 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to create usergroups with a higher rank than your own")
233 return false
234 end
235
236 FAdmin.Access.AddGroup(args[1], admin, privs, immunity) -- Add new group
237 FAdmin.Messages.SendMessage(ply, 4, "Group created")
238 FAdmin.Access.SendGroups()
239
240 return true, args[1]
241end
242
243local function AddPrivilege(ply, cmd, args)
244 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManagePrivileges") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
245
246 local group, priv = args[1], args[2]
247
248 if not FAdmin.Access.Groups[group] or not FAdmin.Access.Privileges[priv] then
249 FAdmin.Messages.SendMessage(ply, 5, "Invalid arguments")
250 return false
251 end
252
253 -- The player cannot add privileges that they themselves do not have
254
255 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
256
257 -- Setting a group with a higher rank than one's own
258 if (not plyGroup or FAdmin.Access.Groups[group].immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
259 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to manage the privileges of a usergroup with a higher rank than your own")
260 return false
261 end
262
263 FAdmin.Access.Groups[group].PRIVS[priv] = true
264
265 MySQLite.query("REPLACE INTO FADMIN_PRIVILEGES VALUES(" .. MySQLite.SQLStr(group) .. ", " .. MySQLite.SQLStr(priv) .. ");")
266 SendUserMessage("FAdmin_AddPriv", player.GetAll(), group, priv)
267 FAdmin.Messages.SendMessage(ply, 4, "Privilege Added!")
268
269 return true, group, priv
270end
271
272local function RemovePrivilege(ply, cmd, args)
273 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManagePrivileges") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
274
275 local group, priv = args[1], args[2]
276 if not FAdmin.Access.Groups[group] or not FAdmin.Access.Privileges[priv] then
277 FAdmin.Messages.SendMessage(ply, 5, "Invalid arguments")
278 return false
279 end
280
281 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
282
283 -- Setting a group with a higher rank than one's own
284 if (not plyGroup or FAdmin.Access.Groups[group].immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
285 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to manage the privileges of a usergroup with a higher rank than your own")
286 return false
287 end
288
289 FAdmin.Access.Groups[group].PRIVS[priv] = nil
290
291 MySQLite.query("DELETE FROM FADMIN_PRIVILEGES WHERE NAME = " .. MySQLite.SQLStr(group) .. " AND PRIVILEGE = " .. MySQLite.SQLStr(priv) .. ";")
292 SendUserMessage("FAdmin_RemovePriv", player.GetAll(), group, priv)
293 FAdmin.Messages.SendMessage(ply, 4, "Privilege Removed!")
294
295 return true, group, priv
296end
297
298function FAdmin.Access.SendGroups(ply)
299 if not FAdmin.Access.Groups then return end
300
301 net.Start("FADMIN_SendGroups")
302 net.WriteTable(FAdmin.Access.Groups)
303 net.Send(IsValid(ply) and ply or player.GetAll())
304end
305
306-- FAdmin SetAccess <player> <groupname> [new_groupadmin, new_groupprivs]
307function FAdmin.Access.SetAccess(ply, cmd, args)
308 if not FAdmin.Access.PlayerHasPrivilege(ply, "SetAccess") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
309
310 local targets = FAdmin.FindPlayer(args[1])
311 local admin = tonumber(args[3])
312 local group = FAdmin.Access.Groups[args[2]]
313 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
314
315 if not args[2] or not group and not admin then
316 FAdmin.Messages.SendMessage(ply, 1, "Group not found")
317 return false
318 elseif args[2] and not group and admin then
319 local privs = {}
320 for priv, am in SortedPairs(FAdmin.Access.Privileges) do
321 if am <= admin + 1 then privs[priv] = true end
322 end
323
324 local immunity = FAdmin.Access.Groups[FAdmin.Access.ADMIN[admin + 1]].immunity
325 -- Creating and setting a group with a higher rank than one's own
326 if (not plyGroup or immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
327 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to assign anyone a usergroup with a higher rank than your own")
328 return false
329 end
330
331 FAdmin.Access.AddGroup(args[2], tonumber(args[3]), privs, immunity) -- Add new group
332 FAdmin.Messages.SendMessage(ply, 4, "Group created")
333 FAdmin.Access.SendGroups()
334 end
335
336 -- Setting a group with a higher rank than one's own
337 if group and (not plyGroup or group.immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
338 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to assign anyone a usergroup with a higher rank than your own")
339 return false
340 end
341
342 if not targets and (string.find(args[1], "^STEAM_[0-9]:[01]:[0-9]+$") or args[1] == "BOT" or (string.find(args[1], "STEAM_") and #args == 6)) then
343 local target, groupname = args[1], args[2]
344 -- The console splits arguments on colons. Very annoying.
345 if args[1] == "STEAM_0" then
346 target = table.concat(args, "", 1, 5)
347 groupname = args[6]
348 end
349 FAdmin.Access.PlayerSetGroup(target, groupname)
350
351 MySQLite.queryValue(string.format("SELECT groupname FROM FAdmin_PlayerGroup WHERE steamid = %s", MySQLite.SQLStr(target)), function(val)
352 CAMI.SignalSteamIDUserGroupChanged(target, val or "user", groupname, "FAdmin")
353 end)
354 FAdmin.Messages.SendMessage(ply, 4, "User access set!")
355 return true, target, groupname
356 elseif not targets then
357 FAdmin.Messages.SendMessage(ply, 1, "Player not found")
358 return false
359 end
360
361 for _, target in pairs(targets) do
362 if not IsValid(target) then continue end
363
364 FAdmin.Access.PlayerSetGroup(target, args[2])
365
366 -- An end user changed the usergroup. Register with CAMI
367 CAMI.SignalUserGroupChanged(target, target:GetUserGroup(), args[2], "FAdmin")
368 end
369
370 FAdmin.Messages.SendMessage(ply, 4, "User access set!")
371 FAdmin.Messages.FireNotification("setaccess", ply, targets, {args[2]})
372 return true, targets, args[2]
373end
374
375--hooks and stuff
376
377hook.Add("PlayerInitialSpawn", "FAdmin_SetAccess", function(ply)
378 MySQLite.queryValue("SELECT groupname FROM FAdmin_PlayerGroup WHERE steamid = " .. MySQLite.SQLStr(ply:SteamID()) .. ";", function(Group)
379 if not Group then return end
380 ply:SetUserGroup(Group)
381
382 if FAdmin.Access.Groups[Group] then
383 ply:FAdmin_SetGlobal("FAdmin_admin", FAdmin.Access.Groups[Group].ADMIN_ACCESS)
384 end
385 end, function(err) ErrorNoHalt(err) MsgN() end)
386 FAdmin.Access.SendGroups(ply)
387end)
388
389local function toggleImmunity(ply, cmd, args)
390 -- ManageGroups privilege because they can handle immunity settings
391 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManageGroups") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
392
393 if not args[1] then FAdmin.Messages.SendMessage(ply, 5, "Invalid argument!") return false end
394 RunConsoleCommand("_FAdmin_immunity", args[1])
395 local OnOff = (tonumber(args[1]) == 1 and "on") or "off"
396 FAdmin.Messages.ActionMessage(ply, player.GetAll(), ply:Nick() .. " turned " .. OnOff .. " admin immunity!", "Admin immunity has been turned " .. OnOff, "Turned admin immunity " .. OnOff)
397
398 return true, OnOff
399end
400
401
402local function setImmunity(ply, cmd, args)
403 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManageGroups") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
404 local group, immunity = args[1], tonumber(args[2])
405
406 if not FAdmin.Access.Groups[group] or not immunity then return false end
407
408 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
409
410 -- Setting a group with a higher rank than one's own
411 if (not plyGroup or FAdmin.Access.Groups[group].immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
412 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to change the immunity of a group with a higher rank than your")
413 return false
414 end
415
416 if immunity > plyGroup.immunity and not FAdmin.Access.PlayerIsHost(ply) then
417 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to set the immunity to any value higher than your own group's immunity")
418 return false
419 end
420
421 FAdmin.Access.Groups[group].immunity = immunity
422 MySQLite.query("REPLACE INTO FAdmin_Immunity VALUES(" .. MySQLite.SQLStr(group) .. ", " .. tonumber(immunity) .. ");")
423
424 FAdmin.Access.SendGroups(ply)
425
426 return true, group, immunity
427end
428
429FAdmin.StartHooks["Access"] = function() --Run all functions that depend on other plugins
430 FAdmin.Commands.AddCommand("setroot", FAdmin.Access.SetRoot)
431 FAdmin.Commands.AddCommand("setaccess", FAdmin.Access.SetAccess)
432
433 FAdmin.Commands.AddCommand("AddGroup", AddGroup)
434
435 FAdmin.Commands.AddCommand("AddPrivilege", AddPrivilege)
436 FAdmin.Commands.AddCommand("RemovePrivilege", RemovePrivilege)
437
438 FAdmin.Commands.AddCommand("immunity", toggleImmunity)
439 FAdmin.Commands.AddCommand("SetImmunity", setImmunity)
440
441 FAdmin.SetGlobalSetting("Immunity", GetConVar("_FAdmin_immunity"):GetBool())
442end