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