· 8 years ago · Jun 27, 2018, 02:36 AM
1--[[
2 Title: Bans
3
4 Ban-related functions and listeners.
5]]
6
7-- ULib default ban message
8ULib.BanMessage = [[
9-------===== [ BANNED ] =====-------
10
11---= Reason =---
12{{REASON}}
13
14---= Time Left =---
15{{TIME_LEFT}} ]]
16
17function ULib.getBanMessage( steamid, banData, templateMessage )
18 banData = banData or ULib.bans[ steamid ]
19 if not banData then return end
20 templateMessage = templateMessage or ULib.BanMessage
21
22 local replacements = {
23 BANNED_BY = "(Unknown)",
24 BAN_START = "(Unknown)",
25 REASON = "(None given)",
26 TIME_LEFT = "(Permaban)",
27 STEAMID = steamid:gsub("%D", ""),
28 STEAMID64 = util.SteamIDTo64( steamid ),
29 }
30
31 if banData.admin and banData.admin ~= "" then
32 replacements.BANNED_BY = banData.admin
33 end
34
35 local time = tonumber( banData.time )
36 if time and time > 0 then
37 replacements.BAN_START = os.date( "%c", time )
38 end
39
40 if banData.reason and banData.reason ~= "" then
41 replacements.REASON = banData.reason
42 end
43
44 local unban = tonumber( banData.unban )
45 if unban and unban > 0 then
46 replacements.TIME_LEFT = ULib.secondsToStringTime( unban - os.time() )
47 end
48
49 return templateMessage:gsub( "{{([%w_]+)}}", replacements )
50end
51
52local function checkBan( steamid64, ip, password, clpassword, name )
53 local steamid = util.SteamIDFrom64( steamid64 )
54 local banData = ULib.bans[ steamid ]
55 if not banData then return end -- Not banned
56
57 -- Nothing useful to show them, go to default message
58 if not banData.admin and not banData.reason and not banData.unban and not banData.time then return end
59
60 local message = ULib.getBanMessage( steamid )
61 Msg(string.format("%s (%s)<%s> was kicked by ULib because they are on the ban list\n", name, steamid, ip))
62 return false, message
63end
64hook.Add( "CheckPassword", "ULibBanCheck", checkBan, HOOK_LOW )
65-- Low priority to allow servers to easily have another ban message addon
66
67
68--[[
69 Function: ban
70
71 Bans a user.
72
73 Parameters:
74
75 ply - The player to ban.
76 time - *(Optional)* The time in minutes to ban the person for, leave nil or 0 for permaban.
77 reason - *(Optional)* The reason for banning
78 admin - *(Optional)* Admin player enacting ban
79
80 Revisions:
81
82 v2.10 - Added support for custom ban list
83]]
84function ULib.ban( ply, time, reason, admin )
85 if not time or type( time ) ~= "number" then
86 time = 0
87 end
88
89 ULib.addBan( ply:SteamID(), time, reason, ply:Name(), admin )
90end
91
92
93--[[
94 Function: kickban
95
96 An alias for <ban>.
97]]
98ULib.kickban = ULib.ban
99
100
101local function escapeOrNull( str )
102 if not str then return "NULL"
103 else return sql.SQLStr(str) end
104end
105
106
107local function writeBan( bandata )
108 sql.Query(
109 "REPLACE INTO ulib_bans (steamid, time, unban, reason, name, admin, modified_admin, modified_time) " ..
110 string.format( "VALUES (%s, %i, %i, %s, %s, %s, %s, %s)",
111 util.SteamIDTo64( bandata.steamID ),
112 bandata.time or 0,
113 bandata.unban or 0,
114 escapeOrNull( bandata.reason ),
115 escapeOrNull( bandata.name ),
116 escapeOrNull( bandata.admin ),
117 escapeOrNull( bandata.modified_admin ),
118 escapeOrNull( bandata.modified_time )
119 )
120 )
121end
122
123
124--[[
125 Function: addBan
126
127 Helper function to store additional data about bans.
128
129 Parameters:
130
131 steamid - Banned player's steamid
132 time - Length of ban in minutes, use 0 for permanant bans
133 reason - *(Optional)* Reason for banning
134 name - *(Optional)* Name of player banned
135 admin - *(Optional)* Admin player enacting the ban
136
137 Revisions:
138
139 2.10 - Initial
140 2.40 - If the steamid is connected, kicks them with the reason given
141]]
142function ULib.addBan( steamid, time, reason, name, admin )
143 if reason == "" then reason = nil end
144
145 local admin_name
146 if admin then
147 admin_name = "(Console)"
148 if admin:IsValid() then
149 admin_name = string.format( "%s(%s)", admin:Name(), admin:SteamID() )
150 end
151 end
152
153 -- Clean up passed data
154 local t = {}
155 local timeNow = os.time()
156 if ULib.bans[ steamid ] then
157 t = ULib.bans[ steamid ]
158 t.modified_admin = admin_name
159 t.modified_time = timeNow
160 else
161 t.admin = admin_name
162 end
163 t.time = t.time or timeNow
164 if time > 0 then
165 t.unban = ( ( time * 60 ) + timeNow )
166 else
167 t.unban = 0
168 end
169 t.reason = reason
170 t.name = name
171 t.steamID = steamid
172
173 ULib.bans[ steamid ] = t
174
175 local strTime = time ~= 0 and ULib.secondsToStringTime( time*60 )
176 local shortReason = "Banned for " .. (strTime or "eternity")
177 if reason then
178 shortReason = shortReason .. ": " .. reason
179 end
180
181 local longReason = shortReason
182 if reason or strTime or admin then -- If we have something useful to show
183 longReason = "\n" .. ULib.getBanMessage( steamid ) .. "\n" -- Newlines because we are forced to show "Disconnect: <msg>."
184 end
185
186 local ply = player.GetBySteamID( steamid )
187 if ply then
188 ULib.kick( ply, longReason, nil, true)
189 end
190
191 -- Remove all semicolons from the reason to prevent command injection
192 shortReason = string.gsub(shortReason, ";", "")
193
194 -- This redundant kick is to ensure they're kicked -- even if they're joining
195 game.ConsoleCommand( string.format( "kickid %s %s\n", steamid, shortReason or "" ) )
196
197 writeBan( t )
198 hook.Call( ULib.HOOK_USER_BANNED, _, steamid, t )
199end
200
201
202--[[
203 Function: unban
204
205 Unbans the given steamid.
206
207 Parameters:
208
209 steamid - The steamid to unban.
210 admin - *(Optional)* Admin player unbanning steamid
211
212 Revisions:
213
214 v2.10 - Initial
215]]
216function ULib.unban( steamid, admin )
217 game.ConsoleCommand( "removeid " .. steamid .. ";writeid\n" ) -- Remove from srcds in case it was stored there
218
219 --ULib banlist
220 ULib.bans[ steamid ] = nil
221 sql.Query( "DELETE FROM ulib_bans WHERE steamid=" .. util.SteamIDTo64( steamid ) )
222 hook.Call( ULib.HOOK_USER_UNBANNED, _, steamid, admin )
223
224end
225
226
227local function nilIfNull(data)
228 if data == "NULL" then return nil
229 else return data end
230end
231
232
233-- Init our bans table
234if not sql.TableExists( "ulib_bans" ) then
235 sql.Query( "CREATE TABLE IF NOT EXISTS ulib_bans ( " ..
236 "steamid INTEGER NOT NULL PRIMARY KEY, " ..
237 "time INTEGER NOT NULL, " ..
238 "unban INTEGER NOT NULL, " ..
239 "reason TEXT, " ..
240 "name TEXT, " ..
241 "admin TEXT, " ..
242 "modified_admin TEXT, " ..
243 "modified_time INTEGER " ..
244 ");" )
245 sql.Query( "CREATE INDEX IDX_ULIB_BANS_TIME ON ulib_bans ( time DESC );" )
246 sql.Query( "CREATE INDEX IDX_ULIB_BANS_UNBAN ON ulib_bans ( unban DESC );" )
247end
248
249local LEGACY_BANS_FILE = "data/ulib/bans.txt"
250--[[
251 Function: getLegacyBans
252
253 Returns bans written by ULib versions prior to 2.7.
254]]
255function ULib.getLegacyBans()
256 if not ULib.fileExists( LEGACY_BANS_FILE ) then
257 return nil
258 end
259
260 local bans, err = ULib.parseKeyValues( ULib.fileRead( LEGACY_BANS_FILE ) )
261
262 if err then
263 return nil
264 else
265 return bans
266 end
267end
268
269local legacy_bans = ULib.getLegacyBans()
270
271
272--[[
273 Function: refreshBans
274
275 Refreshes the ULib bans.
276]]
277function ULib.refreshBans()
278 local results = sql.Query( "SELECT * FROM ulib_bans" )
279
280 ULib.bans = {}
281 if results then
282 for i=1, #results do
283 local r = results[i]
284
285 r.steamID = util.SteamIDFrom64( r.steamid )
286 r.steamid = nil
287 r.reason = nilIfNull( r.reason )
288 r.name = nilIfNull( r.name )
289 r.admin = nilIfNull( r.admin )
290 r.modified_admin = nilIfNull( r.modified_admin )
291 r.modified_time = nilIfNull( r.modified_time )
292 ULib.bans[ r.steamID ] = r
293 end
294 end
295
296 if legacy_bans then
297 sql.Begin()
298 for steamID, bandata in pairs( legacy_bans ) do
299 bandata.steamID = steamID -- Ensure this is set in the data
300 if not ULib.bans[ steamID ] then
301 writeBan( bandata )
302 ULib.bans[ steamID ] = bandata
303 end
304 end
305 sql.Commit()
306
307 Msg( "[ULib] Upgraded bans storage method, moving previous bans file to " .. ULib.backupFile( LEGACY_BANS_FILE ) .. "\n" )
308 ULib.fileDelete( LEGACY_BANS_FILE )
309 legacy_bans = nil
310 end
311end
312hook.Add( "Initialize", "ULibLoadBans", ULib.refreshBans, HOOK_MONITOR_HIGH )