· 9 years ago · Nov 12, 2016, 09:08 AM
1require("tmysql4")
2local DATABASE_HOST = ""
3local DATABASE_PORT = 3306
4local DATABASE_NAME = ""
5local DATABASE_USERNAME = ""
6local DATABASE_PASSWORD = ""
7local DATABASE_TABLE = ""
8
9ULib.ucl.saveiterationtime = 0.25
10ULib.ucl.savedUsers = {};
11
12function ULib_SQL_Connect()
13
14 if not ULib.ucl.db then
15 ULib_SQL_ConnectToDatabase()
16 return
17 end
18
19 /*if not ( ULib.ucl.db:status() == mysqloo.DATABASE_CONNECTED ) then
20 ULib_SQL_ConnectToDatabase()
21 return
22 end*/
23
24end
25
26
27function ULib_SQL_Format( str )
28 if not str then return "NULL" end
29 return string.format( "%q", str )
30end
31
32function Escape( str )
33 if not ULib.ucl.db then
34 Msg( "Not connected to DB.\n" )
35 return
36 end
37
38 if not str then return end
39
40 local esc = ULib.ucl.db:Escape( str )
41 if not esc then
42 return nil
43 end
44 return esc
45end
46
47ULib.ucl.CONNECTED = false;
48
49function ULib_SQL_ConnectToDatabase()
50 ULib.ucl.db, DB_ERROR = tmysql.initialize(DATABASE_HOST, DATABASE_USERNAME, DATABASE_PASSWORD, DATABASE_NAME, DATABASE_PORT)
51
52 if(!ULib.ucl.CONNECTED && DB_ERROR)then
53 ServerLog("Connection to database failed\n")
54 ServerLog("Error: " .. DB_ERROR .. "\n")
55 timer.Simple( 3, ULib_SQL_ConnectToDatabase )
56 else
57 ULib_SQL_CreateTable();
58 ULib_SQL_TryLoad()
59 ULib.ucl.CONNECTED = true;
60 end
61 print("ERRORS", DB_ERROR)
62end
63
64
65function ULib_SQL_CreateTable()
66 local Query = ULib.ucl.db:Query("CREATE TABLE IF NOT EXISTS " .. DATABASE_TABLE .. " ( uid varchar(255), accessblob text, PRIMARY KEY( uid ) );", onSuccess)
67
68 function onSuccess(data)
69 if(!data[1].status)then
70 ServerLog("FAILED CREATING DATABASE TABLE\n")
71 timer.Simple(3, ULib_SQL_Connect )
72 else
73 ServerLog("SUCCESSFULLY CREATED TABLE OR TABLE ALREADY EXISTED\n")
74 ULib_SQL_TryLoad()
75 end
76 end
77end
78
79
80function ULib_SQL_SaveAll( tbl )
81 //if ULib.ucl.db:status() == mysqloo.DATABASE_CONNECTED then
82 for k, v in pairs( tbl ) do
83 local Query = ULib.ucl.db:Query("REPLACE INTO " .. DATABASE_TABLE .. " (uid, accessblob) VALUES ('" .. k .. "', '" .. Escape(util.TableToJSON(v)) .. "');", onSuccess)
84
85 function onSuccess(data)
86 if(!data.status)then
87 ServerLog("FAILED UPDATING (" .. k .. ") to the database\n")
88 else
89 ServerLog("SUCCESSFULLY ADDED/UPDATED (" .. k .. ") to the database\n")
90 end
91 end
92 end
93end
94
95function ULib_SQL_SaveUser( id )
96 local tbl = ULib.ucl.users[ id ]
97 if not tbl then return end
98 if not ULib.ucl.CONNECTED then return end
99 //if ULib.ucl.db:status() == mysqloo.DATABASE_CONNECTED then
100 local Query = ULib.ucl.db:Query("REPLACE INTO " .. DATABASE_TABLE .. " (uid, accessblob) VALUES ('" .. id .. "', '" .. Escape(util.TableToJSON(tbl)) .. "');", onSuccess);
101 function onSuccess( data )
102 if(!data[1].status)then
103 ServerLog("FAILED ADDED/UPDATED (" .. id .. ") to the database\n")
104 else
105 ServerLog("SUCCESSFULLY ADDED/UPDATED (" .. id .. ") to the database\n")
106 end
107 end
108end
109
110function ULib_SQL_WriteUsers( tbl )
111 for k, v in pairs( tbl ) do
112 ULib_SQL_SaveUser( k )
113 tbl[k] = nil
114 break
115 end
116
117 if table.Count( tbl ) > 0 then
118 timer.Simple( ULib.ucl.saveiterationtime, function() ULib_SQL_WriteUsers( tbl ) end )
119 else
120 tbl = nil
121 ULib.ucl.tempusers = nil
122 ULib.ucl.saving = false
123 end
124end
125
126function ULib_SQL_Load()
127 if(ULib.ucl.db || ULib.ucl.CONNECTED)then
128 local Query = ULib.ucl.db:Query("SELECT * FROM " .. DATABASE_TABLE..";", onSuccess)
129 function onSuccess(data)
130 if(data[1].affected > 0 || data[1].status)then
131 ServerLog("Loading UCL Users List from Databases\n");
132 ULib.ucl.users = {};
133 for k, v in pairs( data[1] || {} ) do
134 if(type(v)!="table")then continue; end
135 for k, user in pairs(v) do
136 if(user)then
137 ULib.ucl.users[user.uid] = util.JSONToTable(user.accessblob);
138 ULib.ucl.savedUsers[user.uid] = util.JSONToTable(user.accessblob);
139 end
140 end
141 end
142 else
143 ServerLog("Database unexpectedly offline, attempting to reconnect\n")
144 end
145 end
146 end
147end
148
149function ULib_SQL_LoadUSER(ID)
150 if(ULib.ucl.db || ULib.ucl.CONNECTED)then
151 local Query = ULib.ucl.db:Query("SELECT * FROM " .. DATABASE_TABLE.." WHERE uid = '"..ID.."';", onSuccess)
152 function onSuccess(data)
153 if(data.status)then
154 ULib.ucl.users[user.uid] = util.JSONToTable(user.accessblob);
155
156 else
157 ServerLog("Database unexpectedly offline, attempting to reconnec2t\n")
158 end
159 end
160 end
161end
162
163
164function ULib_SQL_TryLoad()
165 if ULib.ucl.CONNECTED then
166 ULib_SQL_Load()
167 else
168 timer.Simple( 1, ULib_SQL_TryLoad )
169 end
170end
171
172ULib_SQL_Connect()
173ULib_SQL_TryLoad()
174
175-------------------------------------------------------------------
176--[[
177 Title: UCL
178 ULib's Access Control List
179]]
180
181
182local ucl = ULib.ucl -- Make it easier for us to refer to
183
184local accessStrings = ULib.parseKeyValues( ULib.fileRead( ULib.UCL_REGISTERED ) or "" ) or {}
185local accessCategories = {}
186ULib.ucl.accessStrings = accessStrings
187ULib.ucl.accessCategories = accessCategories
188
189-- Helper function to save access string registration to misc_registered.txt
190local function saveAccessStringRegistration()
191 ULib.fileWrite( ULib.UCL_REGISTERED, ULib.makeKeyValues( accessStrings ) )
192end
193
194-- Save what we've got with ucl.groups so far!
195function ucl.saveGroups()
196 for _, groupInfo in pairs( ucl.groups ) do
197 table.sort( groupInfo.allow )
198 end
199
200 ULib.fileWrite( ULib.UCL_GROUPS, ULib.makeKeyValues( ucl.groups ) )
201end
202
203function ucl.saveUsers()
204 if ucl.saving then
205 return
206 end
207
208 ucl.saving = true
209
210 for _, userInfo in pairs( ucl.users ) do
211 table.sort( userInfo.allow )
212 table.sort( userInfo.deny )
213 end
214
215 ucl.tempusers = table.Copy( ucl.users )
216
217 if table.Count( ucl.tempusers ) > 0 then
218 ULib_SQL_WriteUsers( ucl.tempusers )
219 end
220
221 --ULib.fileWrite( ULib.UCL_USERS, ULib.makeKeyValues( ucl.users ) )
222 --ULib_SQL_SaveAll( ucl.users )
223end
224
225function ucl.saveUser( id )
226 ULib_SQL_SaveUser( id )
227end
228
229function reloadGroups()
230 local needsBackup = false
231 local err
232 ucl.groups, err = ULib.parseKeyValues( ULib.removeCommentHeader( ULib.fileRead( ULib.UCL_GROUPS ), "/" ) )
233
234 if not ucl.groups or not ucl.groups[ ULib.ACCESS_ALL ] then
235 needsBackup = true
236 -- Totally messed up! Clear it.
237 local f = "addons/ulib/" .. ULib.UCL_GROUPS
238 if not ULib.fileExists( f ) then
239 Msg( "ULIB PANIC: groups.txt is corrupted and I can't find the default groups.txt file!!\n" )
240 else
241 local err2
242 ucl.groups, err2 = ULib.parseKeyValues( ULib.removeCommentHeader( ULib.fileRead( f ), "/" ) )
243 if not ucl.groups or not ucl.groups[ ULib.ACCESS_ALL ] then
244 Msg( "ULIB PANIC: default groups.txt is corrupt!\n" )
245 err = err2
246 end
247 end
248 if ULib.fileExists( ULib.UCL_REGISTERED ) then
249 ULib.fileDelete( ULib.UCL_REGISTERED ) -- Since we're regnerating we'll need to remove this
250 end
251 accessStrings = {}
252
253 else
254 -- Check to make sure it passes a basic validity test
255 ucl.groups[ ULib.ACCESS_ALL ].inherit_from = nil -- Ensure this is the case
256 for groupName, groupInfo in pairs( ucl.groups ) do
257 if type( groupName ) ~= "string" then
258 needsBackup = true
259 ucl.groups[ groupName ] = nil
260 else
261
262 if type( groupInfo ) ~= "table" then
263 needsBackup = true
264 groupInfo = {}
265 ucl.groups[ groupName ] = groupInfo
266 end
267
268 if type( groupInfo.allow ) ~= "table" then
269 needsBackup = true
270 groupInfo.allow = {}
271 end
272
273 local inherit_from = groupInfo.inherit_from
274 if inherit_from and inherit_from ~= "" and not ucl.groups[ groupInfo.inherit_from ] then
275 needsBackup = true
276 groupInfo.inherit_from = nil
277 end
278
279 -- Check for cycles
280 local group = ucl.groupInheritsFrom( groupName )
281 while group do
282 if group == groupName then
283 needsBackup = true
284 groupInfo.inherit_from = nil
285 end
286 group = ucl.groupInheritsFrom( group )
287 end
288
289 if groupName ~= ULib.ACCESS_ALL and not groupInfo.inherit_from or groupInfo.inherit_from == "" then
290 groupInfo.inherit_from = ULib.ACCESS_ALL -- Clean :)
291 end
292
293 -- Lower case'ify
294 for k, v in pairs( groupInfo.allow ) do
295 if type( k ) == "string" and k:lower() ~= k then
296 groupInfo.allow[ k:lower() ] = v
297 groupInfo.allow[ k ] = nil
298 else
299 groupInfo.allow[ k ] = v
300 end
301 end
302 end
303 end
304 end
305
306 if needsBackup then
307 Msg( "Groups file was not formatted correctly. Attempting to fix and backing up original\n" )
308 if err then
309 Msg( "Error while reading groups file was: " .. err .. "\n" )
310 end
311 Msg( "Original file was backed up to " .. ULib.backupFile( ULib.UCL_GROUPS ) .. "\n" )
312 ucl.saveGroups()
313 end
314end
315reloadGroups()
316
317local function reloadUsers()
318 local needsBackup = false
319 local err
320 ucl.users, err = ULib.parseKeyValues( ULib.removeCommentHeader( ULib.fileRead( ULib.UCL_USERS ), "/" ) )
321
322 -- Check to make sure it passes a basic validity test
323 if not ucl.users then
324 needsBackup = true
325 -- Totally messed up! Clear it.
326 local f = "addons/ulib/" .. ULib.UCL_USERS
327 if not ULib.fileExists( f ) then
328 Msg( "ULIB PANIC: users.txt is corrupted and I can't find the default users.txt file!!\n" )
329 else
330 local err2
331 ucl.users, err2 = ULib.parseKeyValues( ULib.removeCommentHeader( ULib.fileRead( f ), "/" ) )
332 if not ucl.users then
333 Msg( "ULIB PANIC: default users.txt is corrupt!\n" )
334 err = err2
335 end
336 end
337 if ULib.fileExists( ULib.UCL_REGISTERED ) then
338 ULib.fileDelete( ULib.UCL_REGISTERED ) -- Since we're regnerating we'll need to remove this
339 end
340 accessStrings = {}
341
342 else
343 for id, userInfo in pairs( ucl.users ) do
344 if type( id ) ~= "string" then
345 needsBackup = true
346 ucl.users[ id ] = nil
347 else
348
349 if type( userInfo ) ~= "table" then
350 needsBackup = true
351 userInfo = {}
352 ucl.users[ id ] = userInfo
353 end
354
355 if type( userInfo.allow ) ~= "table" then
356 needsBackup = true
357 userInfo.allow = {}
358 end
359
360 if type( userInfo.deny ) ~= "table" then
361 needsBackup = true
362 userInfo.deny = {}
363 end
364
365 if userInfo.group and type( userInfo.group ) ~= "string" then
366 needsBackup = true
367 userInfo.group = nil
368 end
369
370 if userInfo.name and type( userInfo.name ) ~= "string" then
371 needsBackup = true
372 userInfo.name = nil
373 end
374
375 if userInfo.group == "" then userInfo.group = nil end -- Clean :)
376
377 -- Lower case'ify
378 for k, v in pairs( userInfo.allow ) do
379 if type( k ) == "string" and k:lower() ~= k then
380 userInfo.allow[ k:lower() ] = v
381 userInfo.allow[ k ] = nil
382 else
383 userInfo.allow[ k ] = v
384 end
385 end
386
387 for k, v in ipairs( userInfo.deny ) do
388 if type( k ) == "string" and type( v ) == "string" then -- This isn't allowed here
389 table.insert( userInfo.deny, k )
390 userInfo.deny[ k ] = nil
391 else
392 userInfo.deny[ k ] = v
393 end
394 end
395 end
396 end
397 end
398
399 if needsBackup then
400 Msg( "Users file was not formatted correctly. Attempting to fix and backing up original\n" )
401 if err then
402 Msg( "Error while reading groups file was: " .. err .. "\n" )
403 end
404 Msg( "Original file was backed up to " .. ULib.backupFile( ULib.UCL_USERS ) .. "\n" )
405 --ucl.saveUsers()
406 end
407end
408--reloadUsers()
409
410function ULib_SQL_LoadLegacy()
411end
412
413ULib_SQL_LoadLegacy = reloadUsers
414
415concommand.Add( "ulib_loadlegacy", function( ply, com, args )
416 if IsValid(ply) and ply:IsSuperAdmin() then
417 ULib_SQL_LoadLegacy()
418 ucl.saveUsers() --Saving all entries (Loading from Legacy file)
419 else
420 if not IsValid( ply ) then
421 ULib_SQL_LoadLegacy()
422 ucl.saveUsers() --Saving all entries (Loading from Legacy file)
423 end
424 end
425end )
426
427concommand.Add( "ulib_loadlegacy_nousers", function( ply, com, args )
428 if IsValid(ply) and ply:IsSuperAdmin() then
429 ULib_SQL_LoadLegacy()
430 ULib_SQL_DumpUsers()
431 ucl.saveUsers() --Saving all entries (Loading from Legacy file)
432 else
433 if not IsValid( ply ) then
434 ULib_SQL_LoadLegacy()
435 ULib_SQL_DumpUsers()
436 ucl.saveUsers() --Saving all entries (Loading from Legacy file)
437 end
438 end
439end )
440
441function ULib_SQL_DumpUsers()
442 for k, v in pairs( ULib.ucl.users ) do
443 if v.group == "user" then
444 ULib.ucl.users[k] = nil
445 end
446 end
447end
448
449
450--[[
451 Function: ucl.addGroup
452 Adds a new group to the UCL. Automatically saves.
453 Parameters:
454 name - A string of the group name. (IE: superadmin)
455 allows - *(Optional, defaults to empty table)* The allowed access for the group.
456 inherit_from - *(Optional)* A string of a valid group to inherit from
457 Revisions:
458 v2.10 - acl is now an options parameter, added inherit_from.
459 v2.40 - Rewrite, changed parameter list around.
460]]
461function ucl.addGroup( name, allows, inherit_from )
462 ULib.checkArg( 1, "ULib.ucl.addGroup", "string", name )
463 ULib.checkArg( 2, "ULib.ucl.addGroup", {"nil","table"}, allows )
464 ULib.checkArg( 3, "ULib.ucl.addGroup", {"nil","string"}, inherit_from )
465 allows = allows or {}
466 inherit_from = inherit_from or "user"
467
468 if ucl.groups[ name ] then return error( "Group already exists, cannot add again (" .. name .. ")", 2 ) end
469 if inherit_from then
470 if inherit_from == name then return error( "Group cannot inherit from itself", 2 ) end
471 if not ucl.groups[ inherit_from ] then return error( "Invalid group for inheritance (" .. tostring( inherit_from ) .. ")", 2 ) end
472 end
473
474 -- Lower case'ify
475 for k, v in ipairs( allows ) do allows[ k ] = v:lower() end
476
477 ucl.groups[ name ] = { allow=allows, inherit_from=inherit_from }
478 ucl.saveGroups()
479
480 hook.Call( ULib.HOOK_UCLCHANGED )
481end
482
483
484--[[
485 Function: ucl.groupAllow
486 Adds or removes an access tag in the allows for a group. Automatically reprobes, automatically saves.
487 Parameters:
488 name - A string of the group name. (IE: superadmin)
489 access - The string of the access or a table of accesses to add or remove. Access tags can be specified in values in the table for allows.
490 revoke - *(Optional, defaults to false)* A boolean of whether access should be granted or revoked.
491 Returns:
492 A boolean stating whether you changed anything or not.
493 Revisions:
494 v2.40 - Initial.
495]]
496function ucl.groupAllow( name, access, revoke )
497 ULib.checkArg( 1, "ULib.ucl.groupAllow", "string", name )
498 ULib.checkArg( 2, "ULib.ucl.groupAllow", {"string","table"}, access )
499 ULib.checkArg( 3, "ULib.ucl.groupAllow", {"nil","boolean"}, revoke )
500
501 if type( access ) == "string" then access = { access } end
502 if not ucl.groups[ name ] then return error( "Group does not exist for changing access (" .. name .. ")", 2 ) end
503
504 local allow = ucl.groups[ name ].allow
505
506 local changed = false
507 for k, v in pairs( access ) do
508 local access = v:lower()
509 local accesstag
510 if type( k ) == "string" then
511 accesstag = v
512 access = k:lower()
513 end
514
515 if not revoke and (allow[ access ] ~= accesstag or (not accesstag and not ULib.findInTable( allow, access ))) then
516 changed = true
517 if not accesstag then
518 table.insert( allow, access )
519 allow[ access ] = nil -- Ensure no access tag
520 else
521 allow[ access ] = accesstag
522 if ULib.findInTable( allow, access ) then -- Ensure removal of non-access tag version
523 table.remove( allow, ULib.findInTable( allow, access ) )
524 end
525 end
526 elseif revoke and (allow[ access ] or ULib.findInTable( allow, access )) then
527 changed = true
528
529 allow[ access ] = nil -- Remove any accessTags
530 if ULib.findInTable( allow, access ) then
531 table.remove( allow, ULib.findInTable( allow, access ) )
532 end
533 end
534 end
535
536 if changed then
537 for id, userInfo in pairs( ucl.authed ) do
538 local ply = ULib.getPlyByID( id )
539 if ply and ply:CheckGroup( name ) then
540 ULib.queueFunctionCall( hook.Call, ULib.HOOK_UCLAUTH, _, ply ) -- Inform the masses
541 end
542 end
543
544 ucl.saveGroups()
545
546 hook.Call( ULib.HOOK_UCLCHANGED )
547 end
548
549 return changed
550end
551
552
553--[[
554 Function: ucl.renameGroup
555 Renames a group in the UCL. Automatically moves current members, automatically renames inheritances, automatically saves.
556 Parameters:
557 orig - A string of the original group name. (IE: superadmin)
558 new - A string of the new group name. (IE: owner)
559 Revisions:
560 v2.40 - Initial.
561]]
562function ucl.renameGroup( orig, new )
563 ULib.checkArg( 1, "ULib.ucl.renameGroup", "string", orig )
564 ULib.checkArg( 2, "ULib.ucl.renameGroup", "string", new )
565
566 if orig == ULib.ACCESS_ALL then return error( "This group (" .. orig .. ") cannot be renamed!", 2 ) end
567 if not ucl.groups[ orig ] then return error( "Group does not exist for renaming (" .. orig .. ")", 2 ) end
568 if ucl.groups[ new ] then return error( "Group already exists, cannot rename (" .. new .. ")", 2 ) end
569
570 for id, userInfo in pairs( ucl.users ) do
571 if userInfo.group == orig then
572 userInfo.group = new
573 ucl.saveUser( id )
574 end
575 end
576
577 for id, userInfo in pairs( ucl.authed ) do
578 local ply = ULib.getPlyByID( id )
579 if ply and ply:CheckGroup( orig ) then
580 if ply:GetUserGroup() == orig then
581 ULib.queueFunctionCall( ply.SetUserGroup, ply, new ) -- Queued so group will be removed
582 else
583 ULib.queueFunctionCall( hook.Call, ULib.HOOK_UCLAUTH, _, ply ) -- Inform the masses
584 end
585 end
586 end
587
588 ucl.groups[ new ] = ucl.groups[ orig ] -- Copy!
589 ucl.groups[ orig ] = nil
590
591 for _, groupInfo in pairs( ucl.groups ) do
592 if groupInfo.inherit_from == orig then
593 groupInfo.inherit_from = new
594 end
595 end
596
597 --ucl.saveUsers() --Group was changed, saving all users to reflect
598 ucl.saveGroups()
599
600 hook.Call( ULib.HOOK_UCLCHANGED )
601end
602
603
604--[[
605 Function: ucl.setGroupInheritance
606 Sets a group's inheritance in the UCL. Automatically reprobes current members, automatically saves.
607 Parameters:
608 group - A string of the group name. (IE: superadmin)
609 inherit_from - Either a string of the new inheritance group name or nil to remove inheritance. (IE: admin)
610 Revisions:
611 v2.40 - Initial.
612]]
613function ucl.setGroupInheritance( group, inherit_from )
614 ULib.checkArg( 1, "ULib.ucl.renameGroup", "string", group )
615 ULib.checkArg( 2, "ULib.ucl.renameGroup", {"nil","string"}, inherit_from )
616 if inherit_from then
617 if inherit_from == ULib.ACCESS_ALL then inherit_from = nil end -- Implicitly inherited
618 end
619
620 if group == ULib.ACCESS_ALL then return error( "This group (" .. group .. ") cannot have it's inheritance changed!", 2 ) end
621 if not ucl.groups[ group ] then return error( "Group does not exist (" .. group .. ")", 2 ) end
622 if inherit_from and not ucl.groups[ inherit_from ] then return error( "Group for inheritance does not exist (" .. inherit_from .. ")", 2 ) end
623
624 -- Check for cycles
625 local old_inherit = ucl.groups[ group ].inherit_from
626 ucl.groups[ group ].inherit_from = inherit_from -- Temporary!
627 local groupCheck = ucl.groupInheritsFrom( group )
628 while groupCheck do
629 if groupCheck == group then -- Got back to ourselves. This is bad.
630 ucl.groups[ group ].inherit_from = old_inherit -- Set it back
631 error( "Changing group \"" .. group .. "\" inheritance to \"" .. inherit_from .. "\" would cause cyclical inheritance. Aborting.", 2 )
632 end
633 groupCheck = ucl.groupInheritsFrom( groupCheck )
634 end
635 ucl.groups[ group ].inherit_from = old_inherit -- Set it back
636
637 if old_inherit == inherit_from then return end -- Nothing to change
638
639 for id, userInfo in pairs( ucl.authed ) do
640 local ply = ULib.getPlyByID( id )
641 if ply and ply:CheckGroup( group ) then
642 ULib.queueFunctionCall( hook.Call, ULib.HOOK_UCLAUTH, _, ply ) -- Queued so group will be changed
643 end
644 end
645
646 ucl.groups[ group ].inherit_from = inherit_from
647
648 ucl.saveGroups()
649
650 hook.Call( ULib.HOOK_UCLCHANGED )
651end
652
653
654--[[
655 Function: ucl.setGroupCanTarget
656 Sets what a group is allowed to target in the UCL. Automatically saves.
657 Parameters:
658 group - A string of the group name. (IE: superadmin)
659 can_target - Either a string of who the group is allowed to target (IE: !%admin) or nil to clear the restriction.
660 Revisions:
661 v2.40 - Initial.
662]]
663function ucl.setGroupCanTarget( group, can_target )
664 ULib.checkArg( 1, "ULib.ucl.setGroupCanTarget", "string", group )
665 ULib.checkArg( 2, "ULib.ucl.setGroupCanTarget", {"nil","string"}, can_target )
666 if not ucl.groups[ group ] then return error( "Group does not exist (" .. group .. ")", 2 ) end
667
668 if ucl.groups[ group ].can_target == can_target then return end -- Nothing to change
669
670 ucl.groups[ group ].can_target = can_target
671
672 ucl.saveGroups()
673
674 hook.Call( ULib.HOOK_UCLCHANGED )
675end
676
677
678--[[
679 Function: ucl.removeGroup
680 Removes a group from the UCL. Automatically removes this group from members in it, automatically patches inheritances, automatically saves.
681 Parameters:
682 name - A string of the group name. (IE: superadmin)
683 Revisions:
684 v2.10 - Initial.
685 v2.40 - Rewrite, removed write parameter.
686]]
687function ucl.removeGroup( name )
688 ULib.checkArg( 1, "ULib.ucl.removeGroup", "string", name )
689
690 if name == ULib.ACCESS_ALL then return error( "This group (" .. name .. ") cannot be removed!", 2 ) end
691 if not ucl.groups[ name ] then return error( "Group does not exist for removing (" .. name .. ")", 2 ) end
692
693 local inherits_from = ucl.groupInheritsFrom( name )
694 if inherits_from == ULib.ACCESS_ALL then inherits_from = nil end -- Easier
695
696 for id, userInfo in pairs( ucl.users ) do
697 if userInfo.group == name then
698 userInfo.group = inherits_from
699 ucl.saveUsers( id )
700 end
701 end
702
703 for id, userInfo in pairs( ucl.authed ) do
704 local ply = ULib.getPlyByID( id )
705 if ply and ply:CheckGroup( name ) then
706 if ply:GetUserGroup() == name then
707 ULib.queueFunctionCall( ply.SetUserGroup, ply, inherits_from or ULib.ACCESS_ALL ) -- Queued so group will be removed
708 else
709 ULib.queueFunctionCall( hook.Call, ULib.HOOK_UCLAUTH, _, ply ) -- Inform the masses
710 end
711 end
712 end
713
714 ucl.groups[ name ] = nil
715 for _, groupInfo in pairs( ucl.groups ) do
716 if groupInfo.inherit_from == name then
717 groupInfo.inherit_from = inherits_from
718 end
719 end
720
721 --ucl.saveUsers() --Group was removed, saving all users to reflect
722 ucl.saveGroups()
723
724 hook.Call( ULib.HOOK_UCLCHANGED )
725end
726
727--[[
728 Function: ucl.getUserRegisteredID
729 Returns the SteamID, IP, or UniqueID of a player if they're registered under any of those IDs under ucl.users. Checks in order. Returns nil if not registered.
730 Parameters:
731 ply - The player object you wish to check.
732 Revisions:
733 2.41 - Initial.
734]]
735
736function ucl.getUserRegisteredID( ply )
737 local id = ply:SteamID()
738 local uid = ply:UniqueID()
739 local ip = ULib.splitPort( ply:IPAddress() )
740 local checkIndexes = { id, ip, uid }
741 for _, index in ipairs( checkIndexes ) do
742 if ULib.ucl.users[ index ] then
743 return id
744 end
745 end
746end
747
748--[[
749 Function: ucl.addUser
750 Adds a user to the UCL. Automatically probes for the user, automatically saves.
751 Parameters:
752 id - The SteamID, IP, or UniqueID of the user you wish to add.
753 allows - *(Optional, defaults to empty table)* The list of access you wish to give this user.
754 denies - *(Optional, defaults to empty table)* The list of access you wish to explicitly deny this user.
755 group - *(Optional)* The sting of the group this user should belong to. Must be a valid group.
756 Revisions:
757 2.10 - No longer makes a group if it doesn't exist.
758 2.40 - Rewrite, changed the arguments all around.
759]]
760function ucl.addUser( id, allows, denies, group )
761 ULib.checkArg( 1, "ULib.ucl.addUser", "string", id )
762 ULib.checkArg( 2, "ULib.ucl.addUser", {"nil","table"}, allows )
763 ULib.checkArg( 3, "ULib.ucl.addUser", {"nil","table"}, denies )
764 ULib.checkArg( 4, "ULib.ucl.addUser", {"nil","string"}, group )
765
766 id = id:upper() -- In case of steamid, needs to be upper case
767 allows = allows or {}
768 denies = denies or {}
769 if allows == ULib.DEFAULT_GRANT_ACCESS.allow then allows = table.Copy( allows ) end -- Otherwise we'd be changing all guest access
770 if denies == ULib.DEFAULT_GRANT_ACCESS.deny then denies = table.Copy( denies ) end -- Otherwise we'd be changing all guest access
771 if group and not ucl.groups[ group ] then return error( "Group does not exist for adding user to (" .. group .. ")", 2 ) end
772
773 -- Lower case'ify
774 for k, v in ipairs( allows ) do allows[ k ] = v end
775 for k, v in ipairs( denies ) do denies[ k ] = v end
776
777 local name
778 if ucl.users[ id ] and ucl.users[ id ].name then name = ucl.users[ id ].name end -- Preserve name
779 ucl.users[ id ] = { allow=allows, deny=denies, group=group, name=name }
780
781 --ucl.saveUsers() --User was added, only need to save that one user.
782 ucl.saveUser(id)
783
784 local ply = ULib.getPlyByID( id )
785 if ply then
786 ucl.probe( ply )
787 else -- Otherwise this gets called twice
788 hook.Call( ULib.HOOK_UCLCHANGED )
789 end
790end
791
792
793--[[
794 Function: ucl.userAllow
795 Adds or removes an access tag in the allows or denies for a user. Automatically reprobes, automatically saves.
796 Parameters:
797 id - The SteamID, IP, or UniqueID of the user to change. Must be a valid, existing ID, or an ID of a connected player.
798 access - The string of the access or a table of accesses to add or remove. Access tags can be specified in values in the table for allows.
799 revoke - *(Optional, defaults to false)* A boolean of whether the access tag should be added or removed
800 from the allow or deny list. If true, it's removed.
801 deny - *(Optional, defaults to false)* If true, the access is added or removed from the deny list,
802 if false it's added or removed from the allow list.
803 Returns:
804 A boolean stating whether you changed anything or not.
805 Revisions:
806 v2.40 - Initial.
807 v2.50 - Relaxed restrictions on id parameter.
808 v2.51 - Fixed this function not working on disconnected players.
809]]
810function ucl.userAllow( id, access, revoke, deny )
811 ULib.checkArg( 1, "ULib.ucl.userAllow", "string", id )
812 ULib.checkArg( 2, "ULib.ucl.userAllow", {"string","table"}, access )
813 ULib.checkArg( 3, "ULib.ucl.userAllow", {"nil","boolean"}, revoke )
814 ULib.checkArg( 4, "ULib.ucl.userAllow", {"nil","boolean"}, deny )
815
816 id = id:upper() -- In case of steamid, needs to be upper case
817 if type( access ) == "string" then access = { access } end
818
819 local uid = id
820 if not ucl.authed[ uid ] then -- Check to see if it's a steamid or IP
821 local ply = ULib.getPlyByID( id )
822 if ply and ply:IsValid() then
823 uid = ply:UniqueID()
824 end
825 end
826
827 local userInfo = ucl.users[ id ] or ucl.authed[ uid ] -- Check both tables
828 if not userInfo then return error( "User id does not exist for changing access (" .. id .. ")", 2 ) end
829
830 -- If they're connected but don't exist in the ULib user database, add them.
831 -- This can be the case if they're only using the default garrysmod file to pull in users.
832 if userInfo.guest then
833 local allows = {}
834 local denies = {}
835 if not revoke and not deny then allows = access
836 elseif not revoke and deny then denies = access end
837
838 ucl.addUser( id, allows, denies )
839 return true -- And we're done
840 end
841
842 local accessTable = userInfo.allow
843 local otherTable = userInfo.deny
844 if deny then
845 accessTable = userInfo.deny
846 otherTable = userInfo.allow
847 end
848
849 local changed = false
850 for k, v in pairs( access ) do
851 local access = v:lower()
852 local accesstag
853 if type( k ) == "string" then
854 access = k:lower()
855 if not revoke and not deny then -- Not valid to have accessTags unless this is the case
856 accesstag = v
857 end
858 end
859
860 if not revoke and (accessTable[ access ] ~= accesstag or (not accesstag and not ULib.findInTable( accessTable, access ))) then
861 changed = true
862 if not accesstag then
863 table.insert( accessTable, access )
864 accessTable[ access ] = nil -- Ensure no access tag
865 else
866 accessTable[ access ] = accesstag
867 if ULib.findInTable( accessTable, access ) then -- Ensure removal of non-access tag version
868 table.remove( accessTable, ULib.findInTable( accessTable, access ) )
869 end
870 end
871
872 -- If it's on the other table, remove
873 if deny then
874 otherTable[ access ] = nil -- Remove any accessTags
875 end
876 if ULib.findInTable( otherTable, access ) then
877 table.remove( otherTable, ULib.findInTable( otherTable, access ) )
878 end
879
880 elseif revoke and (accessTable[ access ] or ULib.findInTable( accessTable, access )) then
881 changed = true
882
883 if not deny then
884 accessTable[ access ] = nil -- Remove any accessTags
885 end
886 if ULib.findInTable( accessTable, access ) then
887 table.remove( accessTable, ULib.findInTable( accessTable, access ) )
888 end
889 end
890 end
891
892 if changed then
893 local ply = ULib.getPlyByID( id )
894 if ply then
895 ULib.queueFunctionCall( hook.Call, ULib.HOOK_UCLAUTH, _, ply ) -- Inform the masses
896 end
897
898 --ucl.saveUsers() --User's accesses are changed, need only save that one user.
899 ucl.saveUser( id )
900
901 hook.Call( ULib.HOOK_UCLCHANGED )
902 end
903
904 return changed
905end
906
907
908--[[
909 Function: ucl.removeUser
910 Removes a user from the UCL. Automatically probes for the user, automatically saves.
911 Parameters:
912 id - The SteamID, IP, or UniqueID of the user you wish to remove. Must be a valid, existing ID.
913 The unique id of a connected user is always valid.
914 Revisions:
915 v2.40 - Rewrite, removed the write argument.
916]]
917function ucl.removeUser( id )
918 ULib.checkArg( 1, "ULib.ucl.addUser", "string", id )
919 id = id:upper() -- In case of steamid, needs to be upper case
920
921 local userInfo = ucl.users[ id ] or ucl.authed[ id ] -- Check both tables
922 if not userInfo then return error( "User id does not exist for removing (" .. id .. ")", 2 ) end
923
924 local changed = false
925 local q_id = nil --Query Index
926
927 if ucl.authed[ id ] and not ucl.users[ id ] then -- Different ids between offline and authed
928 local ply = ULib.getPlyByID( id )
929 if not ply then return error( "SANITY CHECK FAILED!" ) end -- Should never be invalid
930
931 local ip = ULib.splitPort( ply:IPAddress() )
932 local checkIndexes = { ply:UniqueID(), ip, ply:SteamID() }
933
934 for _, index in ipairs( checkIndexes ) do
935 if ucl.users[ index ] then
936 changed = true
937 ucl.users[ index ] = nil
938 q_id = index
939 break -- Only match the first one
940 end
941 end
942 else
943 changed = true
944 ucl.users[ id ] = nil
945 q_id = id
946 end
947
948 print(changed)
949 print(q_id);
950 if(q_id)then
951 if ULib.ucl.CONNECTED then
952 local query = ULib.ucl.db:Query("DELETE FROM " .. DATABASE_TABLE .. " WHERE uid='" .. Escape(q_id) .. "'", succ)
953 function succ( data )
954 ServerLog("SUCCESSFULLY REMOVED (" .. q_id .. ") from the database\n")
955 end
956 else
957 ServerLog("Database unexpectedly offline, attempting to reconnect\n")
958 ULib_SQL_ConnectToDatabase()
959 end
960end
961 local ply = ULib.getPlyByID( id )
962 if ply then
963 ply:SetUserGroup( ULib.ACCESS_ALL, true )
964 ucl.probe( ply ) -- Reprobe
965 else -- Otherwise this is called twice
966 hook.Call( ULib.HOOK_UCLCHANGED )
967 end
968end
969
970
971--[[
972 Function: ucl.registerAccess
973 Inform UCL about the existence of a particular access string, optionally make it have a certain default access,
974 optionally give a help message along with it. The use of this function is optional, it is not required in order
975 to query an access string, but it's use is highly recommended.
976 Parameters:
977 access - The access string (IE, "ulx slap" or "ups deletionAccess").
978 groups - *(Optional, defaults to no access)* Either a string of a group or a table of groups to give the default access to.
979 comment - *(Optional)* A brief description of what this access string is granting access to.
980 category - *(Optional)* Category for the access string (IE, "Command", "CVAR", "Limits")
981 Revisions:
982 v2.40 - Rewrite.
983]]
984function ucl.registerAccess( access, groups, comment, category )
985 ULib.checkArg( 1, "ULib.ucl.registerAccess", "string", access )
986 ULib.checkArg( 2, "ULib.ucl.registerAccess", {"nil","string","table"}, groups )
987 ULib.checkArg( 3, "ULib.ucl.registerAccess", {"nil","string"}, comment )
988 ULib.checkArg( 4, "ULib.ucl.registerAccess", {"nil","string"}, category )
989
990 access = access:lower()
991 comment = comment or ""
992 if groups == nil then groups = {} end
993 if type( groups ) == "string" then
994 groups = { groups }
995 end
996
997 accessCategories[ access ] = category
998 if accessStrings[ access ] ~= comment then -- Only if not already registered or if the comment has changed
999 accessStrings[ access ] = comment
1000
1001 -- Create a named timer so no matter how many times this function is called in a frame, it's only saved once.
1002 timer.Create( "ULibSaveAccessStrings", 1, 1, saveAccessStringRegistration ) -- 1 sec delay, 1 rep
1003
1004 -- Double check to make sure this isn't already registered with some group somewhere before re-adding it
1005 for _, groupInfo in pairs( ucl.groups ) do
1006 if table.HasValue( groupInfo.allow, access ) then return end -- Found, don't add again
1007 end
1008
1009 for _, group in ipairs( groups ) do
1010 -- Create group if it doesn't exist
1011 if not ucl.groups[ group ] then ucl.addGroup( group ) end
1012
1013 table.insert( ucl.groups[ group ].allow, access )
1014 end
1015
1016 timer.Create( "ULibSaveGroups", 1, 1, ucl.saveGroups ) -- 1 sec delay, 1 rep
1017 end
1018end
1019
1020
1021--[[
1022 Function: ucl.probe
1023 Probes the user to assign access appropriately.
1024 *DO NOT CALL THIS DIRECTLY, UCL HANDLES IT.*
1025 Parameters:
1026 ply - The player object to probe.
1027 Revisions:
1028 v2.40 - Rewrite.
1029]]
1030function ucl.probe( ply )
1031 local ip = ULib.splitPort( ply:IPAddress() )
1032 local uid = ply:UniqueID()
1033 local checkIndexes = { uid, ip, ply:SteamID() }
1034
1035 //ULib_SQL_LoadUSER(uid);
1036
1037
1038 local match = false
1039 for _, index in ipairs( checkIndexes ) do
1040 if ucl.users[ index ] || ULib.ucl.savedUsers[index] then
1041 ucl.authed[ uid ] = ((ucl.users[ index ] && ucl.users[index]) || ULib.ucl.savedUsers[index])-- Setup an ALIAS
1042
1043 -- If they have a group, set it
1044 local group = ucl.authed[ uid ].group
1045 if group and group ~= "" then
1046 ply:SetUserGroup( group, true )
1047 end
1048
1049 -- Update their name
1050 ucl.authed[ uid ].name = ply:Nick()
1051 //ucl.saveUsers() -- Save only the probed player to account for a name change
1052 match = true
1053 break
1054 end
1055 end
1056
1057 if not match then
1058 ucl.authed[ ply:UniqueID() ] = ULib.DEFAULT_GRANT_ACCESS
1059 if ply.tmp_group then
1060 ply:SetUserGroup( ply.tmp_group, true ) -- Make sure they keep the group
1061 ply.tmp_group = nil
1062 end
1063 end
1064
1065 hook.Call( ULib.HOOK_UCLCHANGED )
1066 hook.Call( ULib.HOOK_UCLAUTH, _, ply )
1067end
1068-- Note that this function is hooked into "PlayerAuthed", below.
1069
1070
1071local function botCheck( ply )
1072 if ply:IsBot() and not ucl.authed[ ply:UniqueID() ] then
1073 ply:SetUserGroup( ULib.ACCESS_ALL, true ) -- Give it a group!
1074 ucl.probe( ply )
1075 end
1076end
1077hook.Add( "PlayerInitialSpawn", "ULibSendAuthToClients", botCheck, HOOK_MONITOR_HIGH )
1078
1079local function sendAuthToClients( ply )
1080 ULib.clientRPC( _, "authPlayerIfReady", ply, ply:UserID() ) -- Call on client
1081end
1082hook.Add( ULib.HOOK_UCLAUTH, "ULibSendAuthToClients", sendAuthToClients, HOOK_MONITOR_LOW )
1083
1084local function sendUCLDataToClient( ply )
1085 ULib.clientRPC( ply, "ULib.ucl.initClientUCL", ucl.authed, ucl.groups ) -- Send all UCL data (minus offline users) to all loaded users
1086 ULib.clientRPC( ply, "hook.Call", ULib.HOOK_UCLCHANGED ) -- Call hook on client
1087 ULib.clientRPC( ply, "authPlayerIfReady", ply, ply:UserID() ) -- Call on client
1088end
1089hook.Add( ULib.HOOK_LOCALPLAYERREADY, "ULibSendUCLDataToClient", sendUCLDataToClient, HOOK_MONITOR_HIGH )
1090
1091local function playerDisconnected( ply )
1092 -- We want to perform these actions after everything else has processed through, but we need high priority hook to ensure we don't get sniped.
1093 local uid = ply:UniqueID()
1094 ULib.queueFunctionCall( function()
1095 ULib.ucl.savedUsers[uid] = ucl.authed[ uid ];
1096 ucl.saveUser(uid)
1097 ucl.authed[ uid ] = nil
1098 hook.Call( ULib.HOOK_UCLCHANGED )
1099 ULib_SQL_TryLoad();
1100 end )
1101end
1102hook.Add( "PlayerDisconnected", "ULibUCLDisconnect", playerDisconnected, HOOK_MONITOR_HIGH )
1103
1104local function UCLChanged()
1105 ULib.clientRPC( _, "ULib.ucl.initClientUCL", ucl.authed, ucl.groups ) -- Send all UCL data (minus offline users) to all loaded users
1106 ULib.clientRPC( _, "hook.Call", ULib.HOOK_UCLCHANGED ) -- Call hook on client
1107end
1108hook.Add( ULib.HOOK_UCLCHANGED, "ULibSendUCLToClients", UCLChanged )
1109
1110--[[
1111-- The following is useful for debugging since Garry changes client bootstrapping so frequently
1112hook.Add( ULib.HOOK_UCLCHANGED, "UTEST", function() print( "HERE HERE: UCL Changed" ) end )
1113hook.Add( "PlayerInitialSpawn", "UTEST", function() print( "HERE HERE: Initial Spawn" ) end )
1114hook.Add( "PlayerAuthed", "UTEST", function() print( "HERE HERE: Player Authed" ) end )
1115]]
1116
1117---------- Modify
1118
1119-- Move garry's auth function so it gets called sooner
1120local playerAuth = hook.GetTable().PlayerInitialSpawn.PlayerAuthSpawn
1121hook.Remove( "PlayerInitialSpawn", "PlayerAuthSpawn" ) -- Remove from original spot
1122
1123local function newPlayerAuth( ply, ... )
1124 ucl.authed[ ply:UniqueID() ] = nil -- If the player ent is removed before disconnecting, we can have this hanging out there.
1125 playerAuth( ply, ... ) -- Put here, slightly ahead of ucl.
1126 ucl.probe( ply, ... )
1127end
1128hook.Add( "PlayerAuthed", "ULibAuth", newPlayerAuth, HOOK_MONITOR_HIGH )
1129
1130local meta = FindMetaTable( "Player" )
1131if not meta then return end
1132
1133local oldSetUserGroup = meta.SetUserGroup
1134function meta:SetUserGroup( group, dontCall )
1135 if not ucl.groups[ group ] then ULib.ucl.addGroup( group ) end
1136
1137 local oldGroup = self:GetUserGroup()
1138 oldSetUserGroup( self, group )
1139
1140 if ucl.authed[ self:UniqueID() ] then
1141 if ucl.authed[ self:UniqueID() ] == ULib.DEFAULT_GRANT_ACCESS then
1142 ucl.authed[ self:UniqueID() ] = table.Copy( ULib.DEFAULT_GRANT_ACCESS )
1143 end
1144 ucl.authed[ self:UniqueID() ].group = group
1145 else
1146 self.tmp_group = group
1147 end
1148
1149 ucl.saveUser(self:UniqueID());
1150
1151 if not dontCall and self:GetUserGroup() ~= oldGroup then -- Changed! Inform the masses of the change
1152 hook.Call( ULib.HOOK_UCLCHANGED )
1153 hook.Call( ULib.HOOK_UCLAUTH, _, self )
1154 end
1155end