· 7 years ago · Feb 15, 2019, 02:24 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 if not FAdmin.Access.PlayerHasPrivilege(ply, priv) then
255 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to assign privileges that you don't have yourself")
256 return false
257 end
258
259 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
260
261 -- Setting a group with a higher rank than one's own
262 if (not plyGroup or FAdmin.Access.Groups[group].immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
263 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to manage the privileges of a usergroup with a higher rank than your own")
264 return false
265 end
266
267 FAdmin.Access.Groups[group].PRIVS[priv] = true
268
269 MySQLite.query("REPLACE INTO FADMIN_PRIVILEGES VALUES(" .. MySQLite.SQLStr(group) .. ", " .. MySQLite.SQLStr(priv) .. ");")
270 SendUserMessage("FAdmin_AddPriv", player.GetAll(), group, priv)
271 FAdmin.Messages.SendMessage(ply, 4, "Privilege Added!")
272
273 return true, group, priv
274end
275
276local function RemovePrivilege(ply, cmd, args)
277 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManagePrivileges") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
278
279 local group, priv = args[1], args[2]
280 if not FAdmin.Access.Groups[group] or not FAdmin.Access.Privileges[priv] then
281 FAdmin.Messages.SendMessage(ply, 5, "Invalid arguments")
282 return false
283 end
284
285 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
286
287 -- Setting a group with a higher rank than one's own
288 if (not plyGroup or FAdmin.Access.Groups[group].immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
289 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to manage the privileges of a usergroup with a higher rank than your own")
290 return false
291 end
292
293 FAdmin.Access.Groups[group].PRIVS[priv] = nil
294
295 MySQLite.query("DELETE FROM FADMIN_PRIVILEGES WHERE NAME = " .. MySQLite.SQLStr(group) .. " AND PRIVILEGE = " .. MySQLite.SQLStr(priv) .. ";")
296 SendUserMessage("FAdmin_RemovePriv", player.GetAll(), group, priv)
297 FAdmin.Messages.SendMessage(ply, 4, "Privilege Removed!")
298
299 return true, group, priv
300end
301
302function FAdmin.Access.SendGroups(ply)
303 if not FAdmin.Access.Groups then return end
304
305 net.Start("FADMIN_SendGroups")
306 net.WriteTable(FAdmin.Access.Groups)
307 net.Send(IsValid(ply) and ply or player.GetAll())
308end
309
310-- FAdmin SetAccess <player> <groupname> [new_groupadmin, new_groupprivs]
311function FAdmin.Access.SetAccess(ply, cmd, args)
312 if not FAdmin.Access.PlayerHasPrivilege(ply, "SetAccess") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
313
314 local targets = FAdmin.FindPlayer(args[1])
315 local admin = tonumber(args[3])
316 local group = FAdmin.Access.Groups[args[2]]
317 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
318
319 if not args[2] or not group and not admin then
320 FAdmin.Messages.SendMessage(ply, 1, "Group not found")
321 return false
322 elseif args[2] and not group and admin then
323 local privs = {}
324 for priv, am in SortedPairs(FAdmin.Access.Privileges) do
325 if am <= admin + 1 then privs[priv] = true end
326 end
327
328 local immunity = FAdmin.Access.Groups[FAdmin.Access.ADMIN[admin + 1]].immunity
329 -- Creating and setting a group with a higher rank than one's own
330 if (not plyGroup or immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
331 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to assign anyone a usergroup with a higher rank than your own")
332 return false
333 end
334
335 FAdmin.Access.AddGroup(args[2], tonumber(args[3]), privs, immunity) -- Add new group
336 FAdmin.Messages.SendMessage(ply, 4, "Group created")
337 FAdmin.Access.SendGroups()
338 end
339
340 -- Setting a group with a higher rank than one's own
341 if group and (not plyGroup or group.immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
342 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to assign anyone a usergroup with a higher rank than your own")
343 return false
344 end
345
346 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
347 local target, groupname = args[1], args[2]
348 -- The console splits arguments on colons. Very annoying.
349 if args[1] == "STEAM_0" then
350 target = table.concat(args, "", 1, 5)
351 groupname = args[6]
352 end
353 FAdmin.Access.PlayerSetGroup(target, groupname)
354
355 MySQLite.queryValue(string.format("SELECT groupname FROM FAdmin_PlayerGroup WHERE steamid = %s", MySQLite.SQLStr(target)), function(val)
356 CAMI.SignalSteamIDUserGroupChanged(target, val or "user", groupname, "FAdmin")
357 end)
358 FAdmin.Messages.SendMessage(ply, 4, "User access set!")
359 return true, target, groupname
360 elseif not targets then
361 FAdmin.Messages.SendMessage(ply, 1, "Player not found")
362 return false
363 end
364
365 for _, target in pairs(targets) do
366 if not IsValid(target) then continue end
367
368 FAdmin.Access.PlayerSetGroup(target, args[2])
369
370 -- An end user changed the usergroup. Register with CAMI
371 CAMI.SignalUserGroupChanged(target, target:GetUserGroup(), args[2], "FAdmin")
372 end
373
374 FAdmin.Messages.SendMessage(ply, 4, "User access set!")
375 FAdmin.Messages.FireNotification("setaccess", ply, targets, {args[2]})
376 return true, targets, args[2]
377end
378
379--hooks and stuff
380
381hook.Add("PlayerInitialSpawn", "FAdmin_SetAccess", function(ply)
382 MySQLite.queryValue("SELECT groupname FROM FAdmin_PlayerGroup WHERE steamid = " .. MySQLite.SQLStr(ply:SteamID()) .. ";", function(Group)
383 if not Group then return end
384 ply:SetUserGroup(Group)
385
386 if FAdmin.Access.Groups[Group] then
387 ply:FAdmin_SetGlobal("FAdmin_admin", FAdmin.Access.Groups[Group].ADMIN_ACCESS)
388 end
389 end, function(err) ErrorNoHalt(err) MsgN() end)
390 FAdmin.Access.SendGroups(ply)
391end)
392
393local function toggleImmunity(ply, cmd, args)
394 -- ManageGroups privilege because they can handle immunity settings
395 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManageGroups") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
396
397 if not args[1] then FAdmin.Messages.SendMessage(ply, 5, "Invalid argument!") return false end
398 RunConsoleCommand("_FAdmin_immunity", args[1])
399 local OnOff = (tonumber(args[1]) == 1 and "on") or "off"
400 FAdmin.Messages.ActionMessage(ply, player.GetAll(), ply:Nick() .. " turned " .. OnOff .. " admin immunity!", "Admin immunity has been turned " .. OnOff, "Turned admin immunity " .. OnOff)
401
402 return true, OnOff
403end
404
405
406local function setImmunity(ply, cmd, args)
407 if not FAdmin.Access.PlayerHasPrivilege(ply, "ManageGroups") then FAdmin.Messages.SendMessage(ply, 5, "No access!") return false end
408 local group, immunity = args[1], tonumber(args[2])
409
410 if not FAdmin.Access.Groups[group] or not immunity then return false end
411
412 local plyGroup = FAdmin.Access.Groups[ply:EntIndex() == 0 and "superadmin" or ply:GetUserGroup()]
413
414 -- Setting a group with a higher rank than one's own
415 if (not plyGroup or FAdmin.Access.Groups[group].immunity > plyGroup.immunity) and not FAdmin.Access.PlayerIsHost(ply) then
416 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to change the immunity of a group with a higher rank than your")
417 return false
418 end
419
420 if immunity > plyGroup.immunity and not FAdmin.Access.PlayerIsHost(ply) then
421 FAdmin.Messages.SendMessage(ply, 5, "You're not allowed to set the immunity to any value higher than your own group's immunity")
422 return false
423 end
424
425 FAdmin.Access.Groups[group].immunity = immunity
426 MySQLite.query("REPLACE INTO FAdmin_Immunity VALUES(" .. MySQLite.SQLStr(group) .. ", " .. tonumber(immunity) .. ");")
427
428 FAdmin.Access.SendGroups(ply)
429
430 return true, group, immunity
431end
432
433FAdmin.StartHooks["Access"] = function() --Run all functions that depend on other plugins
434 FAdmin.Commands.AddCommand("setroot", FAdmin.Access.SetRoot)
435 FAdmin.Commands.AddCommand("setaccess", FAdmin.Access.SetAccess)
436
437 FAdmin.Commands.AddCommand("AddGroup", AddGroup)
438
439 FAdmin.Commands.AddCommand("AddPrivilege", AddPrivilege)
440 FAdmin.Commands.AddCommand("RemovePrivilege", RemovePrivilege)
441
442 FAdmin.Commands.AddCommand("immunity", toggleImmunity)
443 FAdmin.Commands.AddCommand("SetImmunity", setImmunity)
444
445 FAdmin.SetGlobalSetting("Immunity", GetConVar("_FAdmin_immunity"):GetBool())
446end