jdarwood007 commited on 2020-01-04 11:24:32
Showing 7 changed files, with 1229 additions and 166 deletions.
... | ... |
@@ -53,10 +53,15 @@ class SFSA |
53 | 53 |
global $smcFunc; |
54 | 54 |
|
55 | 55 |
if (is_null(self::$SFSAclass)) |
56 |
+ { |
|
57 |
+ if (!empty($smcFunc['SFSA'])) |
|
58 |
+ self::$SFSAclass = $smcFunc['SFSA']; |
|
59 |
+ else |
|
56 | 60 |
{ |
57 | 61 |
self::$SFSAclass = new SFSA(); |
58 | 62 |
$smcFunc['SFSA'] = self::$SFSAclass; |
59 | 63 |
} |
64 |
+ } |
|
60 | 65 |
|
61 | 66 |
return self::$SFSAclass; |
62 | 67 |
} |
... | ... |
@@ -0,0 +1,931 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+/** |
|
4 |
+ * The Logs class for Stop Forum Spam |
|
5 |
+ * @package StopForumSpam |
|
6 |
+ * @author SleePy <sleepy @ simplemachines (dot) org> |
|
7 |
+ * @copyright 2019 |
|
8 |
+ * @license 3-Clause BSD https://opensource.org/licenses/BSD-3-Clause |
|
9 |
+ * @version 1.2 |
|
10 |
+ */ |
|
11 |
+class SFSL |
|
12 |
+{ |
|
13 |
+ public static $SFSLclass = null; |
|
14 |
+ private $SFSclass = null; |
|
15 |
+ private $SFSAclass = null; |
|
16 |
+ |
|
17 |
+ /** |
|
18 |
+ * @var string URLS we need to SFS for UI presentation. |
|
19 |
+ */ |
|
20 |
+ private $urlSFSipCheck = 'https://www.stopforumspam.com/ipcheck/%1$s'; |
|
21 |
+ private $urlSFSsearch = 'https://www.stopforumspam.com/search/%1$s'; |
|
22 |
+ |
|
23 |
+ /** |
|
24 |
+ * @var mixed Search area handling. |
|
25 |
+ */ |
|
26 |
+ private $search_types = array(); |
|
27 |
+ private $search_params = array(); |
|
28 |
+ private $search_params_column = ''; |
|
29 |
+ private $search_params_string = null; |
|
30 |
+ private $search_params_type = null; |
|
31 |
+ private $canDeleteLogs = false; |
|
32 |
+ private $logSearch = array(); |
|
33 |
+ |
|
34 |
+ /** |
|
35 |
+ * @var int How long we disable removing logs. |
|
36 |
+ */ |
|
37 |
+ private $hoursDisabled = 24; |
|
38 |
+ |
|
39 |
+ /** |
|
40 |
+ * Creates a self reference to the SFS Log class for use later. |
|
41 |
+ * |
|
42 |
+ * @version 1.2 |
|
43 |
+ * @since 1.2 |
|
44 |
+ * @return object The SFS Log class is returned. |
|
45 |
+ */ |
|
46 |
+ public static function selfClass() |
|
47 |
+ { |
|
48 |
+ global $smcFunc; |
|
49 |
+ |
|
50 |
+ if (is_null(self::$SFSLclass)) |
|
51 |
+ { |
|
52 |
+ if (!empty($smcFunc['SFSL'])) |
|
53 |
+ self::$SFSLclass = $smcFunc['SFSL']; |
|
54 |
+ else |
|
55 |
+ { |
|
56 |
+ self::$SFSLclass = new SFSL(); |
|
57 |
+ $smcFunc['SFSL'] = self::$SFSLclass; |
|
58 |
+ } |
|
59 |
+ } |
|
60 |
+ |
|
61 |
+ return self::$SFSLclass; |
|
62 |
+ } |
|
63 |
+ |
|
64 |
+ /** |
|
65 |
+ * Build the class, figure out what software/version we have. |
|
66 |
+ * Loads up the defaults. |
|
67 |
+ * |
|
68 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
69 |
+ * @version 1.2 |
|
70 |
+ * @since 1.2 |
|
71 |
+ * @return void No return is generated |
|
72 |
+ */ |
|
73 |
+ public function __construct() |
|
74 |
+ { |
|
75 |
+ global $smcFunc; |
|
76 |
+ |
|
77 |
+ $this->SFSclass = &$smcFunc['classSFS']; |
|
78 |
+ $this->SFSAclass = &SFSA::selfClass(); |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ /** |
|
82 |
+ * In some software/versions, we can hook into the logs section. |
|
83 |
+ * In others we hook into the modifications settings. |
|
84 |
+ * |
|
85 |
+ * @param array $log_functions All possible log functions. |
|
86 |
+ * |
|
87 |
+ * @api |
|
88 |
+ * @CalledIn SMF 2.1 |
|
89 |
+ * @See SFSA::startupLogs |
|
90 |
+ * @version 1.2 |
|
91 |
+ * @since 1.0 |
|
92 |
+ * @uses integrate_manage_logs - Hook SMF2.1 |
|
93 |
+ * @return void No return is generated |
|
94 |
+ */ |
|
95 |
+ public static function hook_manage_logs(array &$log_functions): bool |
|
96 |
+ { |
|
97 |
+ // Add our logs sub action. |
|
98 |
+ $log_functions['sfslog'] = array('SFS-Subs-Logs.php', 'startupLogs'); |
|
99 |
+ |
|
100 |
+ return self::selfClass()->AddToLogMenu($log_functions); |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ /** |
|
104 |
+ * Add the SFS logs to the log menu. |
|
105 |
+ * |
|
106 |
+ * @param array $log_functions All possible log functions. |
|
107 |
+ * |
|
108 |
+ * @CalledIn SMF 2.1 |
|
109 |
+ * @See SFSA::startupLogs |
|
110 |
+ * @version 1.1 |
|
111 |
+ * @since 1.1 |
|
112 |
+ * @return void No return is generated |
|
113 |
+ */ |
|
114 |
+ public function AddToLogMenu(array &$log_functions): bool |
|
115 |
+ { |
|
116 |
+ global $context; |
|
117 |
+ |
|
118 |
+ $context[$context['admin_menu_name']]['tab_data']['tabs']['sfslog'] = array( |
|
119 |
+ 'description' => $this->SFSclass->txt('sfs_admin_logs'), |
|
120 |
+ ); |
|
121 |
+ |
|
122 |
+ return true; |
|
123 |
+ } |
|
124 |
+ |
|
125 |
+ /** |
|
126 |
+ * Log startup caller. |
|
127 |
+ * This has a $return_config just for simply complying with properly for searching the admin panel. |
|
128 |
+ * |
|
129 |
+ * @param bool $return_config If true, returns empty array to prevent breaking old SMF installs. |
|
130 |
+ * |
|
131 |
+ * @api |
|
132 |
+ * @CalledIn SMF 2.1 |
|
133 |
+ * @See SFSA::loadLogs |
|
134 |
+ * @version 1.2 |
|
135 |
+ * @since 1.0 |
|
136 |
+ * @uses hook_manage_logs - Hook SMF2.1 |
|
137 |
+ * @uses setupModifyModifications - Injected SMF2.0 |
|
138 |
+ * @return void No return is generated |
|
139 |
+ */ |
|
140 |
+ public static function startupLogs(bool $return_config = false): array |
|
141 |
+ { |
|
142 |
+ return self::selfClass()->loadLogs(); |
|
143 |
+ } |
|
144 |
+ |
|
145 |
+ /** |
|
146 |
+ * Actually show the logs. |
|
147 |
+ * This has a $return_config just for simply complying with properly for searching the admin panel. |
|
148 |
+ * |
|
149 |
+ * @param bool $return_config If true, returns empty array to prevent breaking old SMF installs. |
|
150 |
+ * |
|
151 |
+ * @api |
|
152 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
153 |
+ * @See SFSA::getSFSLogEntries |
|
154 |
+ * @See SFSA::getSFSLogEntriesCount |
|
155 |
+ * @version 1.2 |
|
156 |
+ * @since 1.0 |
|
157 |
+ * @uses hook_manage_logs - Hook SMF2.1 |
|
158 |
+ * @uses setupModifyModifications - Injected SMF2.0 |
|
159 |
+ * @return void No return is generated |
|
160 |
+ */ |
|
161 |
+ public function loadLogs(bool $return_config = false): array |
|
162 |
+ { |
|
163 |
+ global $context, $smcFunc, $sourcedir; |
|
164 |
+ |
|
165 |
+ // No Configs. |
|
166 |
+ if ($return_config) |
|
167 |
+ return array(); |
|
168 |
+ |
|
169 |
+ loadLanguage('Modlog'); |
|
170 |
+ |
|
171 |
+ $context['form_url'] = $this->SFSA->get('adminLogURL'); |
|
172 |
+ $context['log_url'] = $this->SFSA->get('adminLogURL'); |
|
173 |
+ $context['page_title'] = $this->SFSclass->txt('sfs_admin_logs'); |
|
174 |
+ $this->canDeleteLogs = allowedTo('admin_forum'); |
|
175 |
+ |
|
176 |
+ // Remove all.. |
|
177 |
+ if ((isset($_POST['removeall']) || isset($_POST['delete'])) && $this->canDeleteLogs) |
|
178 |
+ $this->handleLogDeletes(); |
|
179 |
+ |
|
180 |
+ $sort_types = $this->handleLogsGetSortTypes(); |
|
181 |
+ |
|
182 |
+ $context['order'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $_REQUEST['sort'] : 'time'; |
|
183 |
+ |
|
184 |
+ // Handle searches. |
|
185 |
+ $this->handleLogSearch($context['log_url']); |
|
186 |
+ |
|
187 |
+ require_once($sourcedir . '/Subs-List.php'); |
|
188 |
+ |
|
189 |
+ $listOptions = array( |
|
190 |
+ 'id' => 'sfslog_list', |
|
191 |
+ 'title' => $this->SFSclass->txt('sfs_admin_logs'), |
|
192 |
+ 'width' => '100%', |
|
193 |
+ 'items_per_page' => '50', |
|
194 |
+ 'no_items_label' => $this->SFSclass->txt('sfs_log_no_entries_found'), |
|
195 |
+ 'base_href' => $context['log_url'], |
|
196 |
+ 'default_sort_col' => 'time', |
|
197 |
+ 'get_items' => $this->loadLogsGetItems(), |
|
198 |
+ 'get_count' => $this->loadLogsGetCount(), |
|
199 |
+ // This assumes we are viewing by user. |
|
200 |
+ 'columns' => array( |
|
201 |
+ 'type' => $this->loadLogsColumnType(), |
|
202 |
+ 'time' => $this->loadLogsColumnTime(), |
|
203 |
+ 'url' => $this->loadLogsColumnURL(), |
|
204 |
+ 'member' => $this->loadLogsColumnMember(), |
|
205 |
+ 'username' => $this->loadLogsColumnUsername(), |
|
206 |
+ 'email' => $this->loadLogsColumnEmail(), |
|
207 |
+ 'ip' => $this->loadLogsColumnIP(), |
|
208 |
+ 'ip2' => $this->loadLogsColumnIP(true), |
|
209 |
+ 'checks' => $this->loadLogsColumnChecks(), |
|
210 |
+ 'result' => $this->loadLogsColumnResult(), |
|
211 |
+ 'delete' => $this->loadLogsColumnDelete(), |
|
212 |
+ ), |
|
213 |
+ 'form' => array( |
|
214 |
+ 'href' => $context['form_url'], |
|
215 |
+ 'include_sort' => true, |
|
216 |
+ 'include_start' => true, |
|
217 |
+ 'hidden_fields' => array( |
|
218 |
+ $context['session_var'] => $context['session_id'], |
|
219 |
+ 'params' => $this->search_params |
|
220 |
+ ), |
|
221 |
+ ), |
|
222 |
+ 'additional_rows' => array( |
|
223 |
+ $this->loadLogsGetAddtionalRow(), |
|
224 |
+ ), |
|
225 |
+ ); |
|
226 |
+ |
|
227 |
+ // Create the watched user list. |
|
228 |
+ createList($listOptions); |
|
229 |
+ |
|
230 |
+ $context['sub_template'] = 'show_list'; |
|
231 |
+ $context['default_list'] = 'sfslog_list'; |
|
232 |
+ |
|
233 |
+ return array(); |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ /** |
|
237 |
+ * Handle when we want to delete a log and what to do. |
|
238 |
+ * |
|
239 |
+ * @internal |
|
240 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
241 |
+ * @version 1.1 |
|
242 |
+ * @since 1.1 |
|
243 |
+ * @return void Nothing is returned, the logs are deleted as requested and admin redirected. |
|
244 |
+ */ |
|
245 |
+ private function handleLogDeletes(): void |
|
246 |
+ { |
|
247 |
+ if (isset($_POST['removeall']) && $this->canDeleteLogs) |
|
248 |
+ $this->removeAllLogs(); |
|
249 |
+ elseif (!empty($_POST['remove']) && isset($_POST['delete']) && $this->canDeleteLogs) |
|
250 |
+ $this->removeLogs(array_unique($_POST['delete'])); |
|
251 |
+ } |
|
252 |
+ |
|
253 |
+ /** |
|
254 |
+ * loadLogs - Sort Types. |
|
255 |
+ * |
|
256 |
+ * @internal |
|
257 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
258 |
+ * @version 1.2 |
|
259 |
+ * @since 1.2 |
|
260 |
+ * @return array The valid Sort Types. |
|
261 |
+ */ |
|
262 |
+ private function handleLogsGetSortTypes(): array |
|
263 |
+ { |
|
264 |
+ return array( |
|
265 |
+ 'id_type' =>'l.id_type', |
|
266 |
+ 'log_time' => 'l.log_time', |
|
267 |
+ 'url' => 'l.url', |
|
268 |
+ 'member' => 'mem.id_member', |
|
269 |
+ 'username' => 'l.username', |
|
270 |
+ 'email' => 'l.email', |
|
271 |
+ 'ip' => 'l.ip', |
|
272 |
+ 'ip2' => 'l.ip2', |
|
273 |
+ ); |
|
274 |
+ } |
|
275 |
+ |
|
276 |
+ /** |
|
277 |
+ * loadLogs - Get Items. |
|
278 |
+ * |
|
279 |
+ * @internal |
|
280 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
281 |
+ * @version 1.1 |
|
282 |
+ * @since 1.1 |
|
283 |
+ * @return array The options for the get_items |
|
284 |
+ */ |
|
285 |
+ private function loadLogsGetItems(): array |
|
286 |
+ { |
|
287 |
+ return array( |
|
288 |
+ 'function' => array($this, 'getSFSLogEntries'), |
|
289 |
+ 'params' => array( |
|
290 |
+ (!empty($this->logSearch['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''), |
|
291 |
+ array('sql_type' => $this->search_params_column, 'search_string' => $this->logSearch['string']), |
|
292 |
+ ), |
|
293 |
+ ); |
|
294 |
+ } |
|
295 |
+ |
|
296 |
+ /** |
|
297 |
+ * loadLogs - Get Count. |
|
298 |
+ * |
|
299 |
+ * @internal |
|
300 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
301 |
+ * @version 1.1 |
|
302 |
+ * @since 1.1 |
|
303 |
+ * @return array The options for the get_items |
|
304 |
+ */ |
|
305 |
+ private function loadLogsGetCount(): array |
|
306 |
+ { |
|
307 |
+ return array( |
|
308 |
+ 'function' => array($this, 'getSFSLogEntriesCount'), |
|
309 |
+ 'params' => array( |
|
310 |
+ (!empty($this->logSearch['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''), |
|
311 |
+ array('sql_type' => $this->search_params_column, 'search_string' => $this->logSearch['string']), |
|
312 |
+ ), |
|
313 |
+ ); |
|
314 |
+ } |
|
315 |
+ |
|
316 |
+ /** |
|
317 |
+ * loadLogs - Load an additional row, for mostly deleting stuff. |
|
318 |
+ * |
|
319 |
+ * @internal |
|
320 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
321 |
+ * @version 1.1 |
|
322 |
+ * @since 1.1 |
|
323 |
+ * @return array The options for the get_items |
|
324 |
+ */ |
|
325 |
+ private function loadLogsGetAddtionalRow(): array |
|
326 |
+ { |
|
327 |
+ global $smcFunc; |
|
328 |
+ |
|
329 |
+ return array( |
|
330 |
+ 'position' => 'below_table_data', |
|
331 |
+ 'value' => ' |
|
332 |
+ ' . $this->SFSclass->txt('sfs_log_search') . ' (' . $this->logSearch['label'] . '): |
|
333 |
+ <input type="text" name="search" size="18" value="' . $smcFunc['htmlspecialchars']($this->logSearch['string']) . '" class="input_text" /> <input type="submit" name="is_search" value="' . $this->SFSclass->txt('modlog_go') . '" class="button_submit" /> |
|
334 |
+ ' . ($this->canDeleteLogs ? ' | |
|
335 |
+ <input type="submit" name="remove" value="' . $this->SFSclass->txt('modlog_remove') . '" class="button_submit" /> |
|
336 |
+ <input type="submit" name="removeall" value="' . $this->SFSclass->txt('modlog_removeall') . '" class="button_submit" />' : ''), |
|
337 |
+ ); |
|
338 |
+ } |
|
339 |
+ |
|
340 |
+ |
|
341 |
+ /** |
|
342 |
+ * loadLogs - Column - Type. |
|
343 |
+ * |
|
344 |
+ * @internal |
|
345 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
346 |
+ * @version 1.1 |
|
347 |
+ * @since 1.1 |
|
348 |
+ * @return array The options for the column |
|
349 |
+ */ |
|
350 |
+ private function loadLogsColumnType(): array |
|
351 |
+ { |
|
352 |
+ return array( |
|
353 |
+ 'header' => array( |
|
354 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_type'), |
|
355 |
+ 'class' => 'lefttext', |
|
356 |
+ ), |
|
357 |
+ 'data' => array( |
|
358 |
+ 'db' => 'type', |
|
359 |
+ 'class' => 'smalltext', |
|
360 |
+ ), |
|
361 |
+ 'sort' => array( |
|
362 |
+ ), |
|
363 |
+ ); |
|
364 |
+ } |
|
365 |
+ |
|
366 |
+ /** |
|
367 |
+ * loadLogs - Column - Time. |
|
368 |
+ * |
|
369 |
+ * @internal |
|
370 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
371 |
+ * @version 1.1 |
|
372 |
+ * @since 1.1 |
|
373 |
+ * @return array The options for the column |
|
374 |
+ */ |
|
375 |
+ private function loadLogsColumnTime(): array |
|
376 |
+ { |
|
377 |
+ return array( |
|
378 |
+ 'header' => array( |
|
379 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_time'), |
|
380 |
+ 'class' => 'lefttext', |
|
381 |
+ ), |
|
382 |
+ 'data' => array( |
|
383 |
+ 'db' => 'time', |
|
384 |
+ 'class' => 'smalltext', |
|
385 |
+ ), |
|
386 |
+ 'sort' => array( |
|
387 |
+ 'default' => 'l.log_time DESC', |
|
388 |
+ 'reverse' => 'l.log_time', |
|
389 |
+ ), |
|
390 |
+ ); |
|
391 |
+ } |
|
392 |
+ |
|
393 |
+ /** |
|
394 |
+ * loadLogs - Column - URL. |
|
395 |
+ * |
|
396 |
+ * @internal |
|
397 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
398 |
+ * @version 1.1 |
|
399 |
+ * @since 1.1 |
|
400 |
+ * @return array The options for the column |
|
401 |
+ */ |
|
402 |
+ private function loadLogsColumnURL(): array |
|
403 |
+ { |
|
404 |
+ return array( |
|
405 |
+ 'header' => array( |
|
406 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_url'), |
|
407 |
+ 'class' => 'lefttext', |
|
408 |
+ ), |
|
409 |
+ 'data' => array( |
|
410 |
+ 'db' => 'url', |
|
411 |
+ 'class' => 'smalltext', |
|
412 |
+ 'style' => 'word-break: break-word;', |
|
413 |
+ ), |
|
414 |
+ 'sort' => array( |
|
415 |
+ 'default' => 'l.url DESC', |
|
416 |
+ 'reverse' => 'l.url', |
|
417 |
+ ), |
|
418 |
+ ); |
|
419 |
+ } |
|
420 |
+ |
|
421 |
+ /** |
|
422 |
+ * loadLogs - Column - Member. |
|
423 |
+ * |
|
424 |
+ * @internal |
|
425 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
426 |
+ * @version 1.1 |
|
427 |
+ * @since 1.1 |
|
428 |
+ * @return array The options for the column |
|
429 |
+ */ |
|
430 |
+ private function loadLogsColumnMember(): array |
|
431 |
+ { |
|
432 |
+ return array( |
|
433 |
+ 'header' => array( |
|
434 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_member'), |
|
435 |
+ 'class' => 'lefttext', |
|
436 |
+ ), |
|
437 |
+ 'data' => array( |
|
438 |
+ 'db' => 'member_link', |
|
439 |
+ 'class' => 'smalltext', |
|
440 |
+ ), |
|
441 |
+ 'sort' => array( |
|
442 |
+ 'default' => 'mem.id_member', |
|
443 |
+ 'reverse' => 'mem.id_member DESC', |
|
444 |
+ ), |
|
445 |
+ ); |
|
446 |
+ } |
|
447 |
+ |
|
448 |
+ /** |
|
449 |
+ * loadLogs - Column - Username. |
|
450 |
+ * |
|
451 |
+ * @internal |
|
452 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
453 |
+ * @version 1.1 |
|
454 |
+ * @since 1.1 |
|
455 |
+ * @return array The options for the column |
|
456 |
+ */ |
|
457 |
+ private function loadLogsColumnUsername(): array |
|
458 |
+ { |
|
459 |
+ return array( |
|
460 |
+ 'header' => array( |
|
461 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_username'), |
|
462 |
+ 'class' => 'lefttext', |
|
463 |
+ ), |
|
464 |
+ 'data' => array( |
|
465 |
+ 'db' => 'username', |
|
466 |
+ 'class' => 'smalltext', |
|
467 |
+ ), |
|
468 |
+ 'sort' => array( |
|
469 |
+ 'default' => 'l.username', |
|
470 |
+ 'reverse' => 'l.username DESC', |
|
471 |
+ ), |
|
472 |
+ ); |
|
473 |
+ } |
|
474 |
+ |
|
475 |
+ /** |
|
476 |
+ * loadLogs - Column - Email. |
|
477 |
+ * |
|
478 |
+ * @internal |
|
479 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
480 |
+ * @version 1.1 |
|
481 |
+ * @since 1.1 |
|
482 |
+ * @return array The options for the column |
|
483 |
+ */ |
|
484 |
+ private function loadLogsColumnEmail(): array |
|
485 |
+ { |
|
486 |
+ return array( |
|
487 |
+ 'header' => array( |
|
488 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_email'), |
|
489 |
+ 'class' => 'lefttext', |
|
490 |
+ ), |
|
491 |
+ 'data' => array( |
|
492 |
+ 'db' => 'email', |
|
493 |
+ 'class' => 'smalltext', |
|
494 |
+ ), |
|
495 |
+ 'sort' => array( |
|
496 |
+ 'default' => 'l.email', |
|
497 |
+ 'reverse' => 'l.email DESC', |
|
498 |
+ ), |
|
499 |
+ ); |
|
500 |
+ } |
|
501 |
+ |
|
502 |
+ /** |
|
503 |
+ * loadLogs - Column - IP. |
|
504 |
+ * |
|
505 |
+ * @param string $ip2 If true, use ip2 |
|
506 |
+ * @internal |
|
507 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
508 |
+ * @version 1.1 |
|
509 |
+ * @since 1.1 |
|
510 |
+ * @return array The options for the column |
|
511 |
+ */ |
|
512 |
+ private function loadLogsColumnIP(bool $ip2 = false): array |
|
513 |
+ { |
|
514 |
+ return array( |
|
515 |
+ 'header' => array( |
|
516 |
+ 'value' => $this->SFSclass->txt('sfs_log_header_ip' . ($ip2 ? '2' : '')), |
|
517 |
+ 'class' => 'lefttext', |
|
518 |
+ ), |
|
519 |
+ 'data' => array( |
|
520 |
+ 'db' => 'ip' . ($ip2 ? '2' : ''), |
|
521 |
+ 'class' => 'smalltext', |
|
522 |
+ ), |
|
523 |
+ 'sort' => array( |
|
524 |
+ 'default' => 'l.ip' . ($ip2 ? '2' : ''), |
|
525 |
+ 'reverse' => 'l.ip' . ($ip2 ? '2' : '') . ' DESC', |
|
526 |
+ ), |
|
527 |
+ ); |
|
528 |
+ } |
|
529 |
+ |
|
530 |
+ /** |
|
531 |
+ * loadLogs - Column - Checks. |
|
532 |
+ * |
|
533 |
+ * @internal |
|
534 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
535 |
+ * @version 1.1 |
|
536 |
+ * @since 1.1 |
|
537 |
+ * @return array The options for the column |
|
538 |
+ */ |
|
539 |
+ private function loadLogsColumnChecks(): array |
|
540 |
+ { |
|
541 |
+ return array( |
|
542 |
+ 'header' => array( |
|
543 |
+ 'value' => $this->SFSclass->txt('sfs_log_checks'), |
|
544 |
+ 'class' => 'lefttext', |
|
545 |
+ ), |
|
546 |
+ 'data' => array( |
|
547 |
+ 'db' => 'checks', |
|
548 |
+ 'class' => 'smalltext', |
|
549 |
+ 'style' => 'word-break: break-word;', |
|
550 |
+ ), |
|
551 |
+ 'sort' => array(), |
|
552 |
+ ); |
|
553 |
+ } |
|
554 |
+ |
|
555 |
+ /** |
|
556 |
+ * loadLogs - Column - Result. |
|
557 |
+ * |
|
558 |
+ * @internal |
|
559 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
560 |
+ * @version 1.1 |
|
561 |
+ * @since 1.1 |
|
562 |
+ * @return array The options for the column |
|
563 |
+ */ |
|
564 |
+ private function loadLogsColumnResult(): array |
|
565 |
+ { |
|
566 |
+ return array( |
|
567 |
+ 'header' => array( |
|
568 |
+ 'value' => $this->SFSclass->txt('sfs_log_result'), |
|
569 |
+ 'class' => 'lefttext', |
|
570 |
+ ), |
|
571 |
+ 'data' => array( |
|
572 |
+ 'db' => 'result', |
|
573 |
+ 'class' => 'smalltext', |
|
574 |
+ 'style' => 'word-break: break-word;', |
|
575 |
+ ), |
|
576 |
+ 'sort' => array(), |
|
577 |
+ ); |
|
578 |
+ } |
|
579 |
+ |
|
580 |
+ /** |
|
581 |
+ * loadLogs - Column - Delete. |
|
582 |
+ * |
|
583 |
+ * @internal |
|
584 |
+ * @CalledIn SMF2.0, SMF 2.1 |
|
585 |
+ * @version 1.1 |
|
586 |
+ * @since 1.1 |
|
587 |
+ * @return array The options for the column |
|
588 |
+ */ |
|
589 |
+ private function loadLogsColumnDelete(): array |
|
590 |
+ { |
|
591 |
+ return array( |
|
592 |
+ 'header' => array( |
|
593 |
+ 'value' => '<input type="checkbox" name="all" class="input_check" onclick="invertAll(this, this.form);" />', |
|
594 |
+ ), |
|
595 |
+ 'data' => array( |
|
596 |
+ 'function' => function($entry) |
|
597 |
+ { |
|
598 |
+ return '<input type="checkbox" class="input_check" name="delete[]" value="' . $entry['id'] . '"' . ($entry['editable'] ? '' : ' disabled="disabled"') . ' />'; |
|
599 |
+ }, |
|
600 |
+ 'style' => 'text-align: center;', |
|
601 |
+ ), |
|
602 |
+ ); |
|
603 |
+ } |
|
604 |
+ |
|
605 |
+ /** |
|
606 |
+ * Get the log data and returns it ready to go for GenericList handling. |
|
607 |
+ * |
|
608 |
+ * @param int $start The index for where we offset or start at for the list |
|
609 |
+ * @param int $items_per_page How many items we are going to show on this page. |
|
610 |
+ * @param string $sort The column we are sorting by. |
|
611 |
+ * @param string $query_string The search string we are using to filter log data. |
|
612 |
+ * @param array $query_params Extra parameters for searching. |
|
613 |
+ * |
|
614 |
+ * @api |
|
615 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
616 |
+ * @See SFSA::loadLogs |
|
617 |
+ * @version 1.2 |
|
618 |
+ * @since 1.0 |
|
619 |
+ * @uses hook_manage_logs - Hook SMF2.1 |
|
620 |
+ * @uses setupModifyModifications - Injected SMF2.0 |
|
621 |
+ * @return void No return is generated |
|
622 |
+ */ |
|
623 |
+ public function getSFSLogEntries(int $start, int $items_per_page, string $sort, string $query_string = '', array $query_params = array()): array |
|
624 |
+ { |
|
625 |
+ global $scripturl, $context, $smcFunc; |
|
626 |
+ |
|
627 |
+ // Fetch all of our logs. |
|
628 |
+ $result = $smcFunc['db_query']('', ' |
|
629 |
+ SELECT |
|
630 |
+ l.id_sfs, l.id_type, l.log_time, l.url, l.id_member, l.username, l.email, l.ip, l.ip2, l.checks, l.result, |
|
631 |
+ mem.real_name, mg.group_name |
|
632 |
+ FROM {db_prefix}log_sfs AS l |
|
633 |
+ LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = l.id_member) |
|
634 |
+ LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END) |
|
635 |
+ WHERE id_type IS NOT NULL' |
|
636 |
+ . (!empty($query_string) ? ' |
|
637 |
+ AND ' . $query_string : '') . ' |
|
638 |
+ ORDER BY ' . $sort . ' |
|
639 |
+ LIMIT {int:start}, {int:items_per_page}', |
|
640 |
+ array_merge($query_params, array( |
|
641 |
+ 'start' => $start, |
|
642 |
+ 'items_per_page' => $items_per_page, |
|
643 |
+ 'reg_group_id' => 0, |
|
644 |
+ )) |
|
645 |
+ ); |
|
646 |
+ |
|
647 |
+ $entries = array(); |
|
648 |
+ while ($row = $smcFunc['db_fetch_assoc']($result)) |
|
649 |
+ $entries[$row['id_sfs']] => $this->getSFSLogPrepareEntry($row); |
|
650 |
+ $smcFunc['db_free_result']($result); |
|
651 |
+ |
|
652 |
+ return $entries; |
|
653 |
+ } |
|
654 |
+ |
|
655 |
+ /** |
|
656 |
+ * Formats a log entry for display. |
|
657 |
+ * |
|
658 |
+ * @param array $row The raw row data. |
|
659 |
+ * |
|
660 |
+ * @api |
|
661 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
662 |
+ * @See SFSA::getSFSLogEntries |
|
663 |
+ * @version 1.2 |
|
664 |
+ * @since 1.2 |
|
665 |
+ * @return array An array of data ready to be sent to output |
|
666 |
+ */ |
|
667 |
+ public function getSFSLogPrepareEntry(array $row = array()): array |
|
668 |
+ { |
|
669 |
+ $return = array( |
|
670 |
+ 'id' => $row['id_sfs'], |
|
671 |
+ 'type' => $this->SFSclass->txt('sfs_log_types_' . $row['id_type']), |
|
672 |
+ 'time' => timeformat($row['log_time']), |
|
673 |
+ 'url' => preg_replace('~http(s)?://~i', 'hxxp\\1://', $row['url']), |
|
674 |
+ 'timestamp' => forum_time(true, $row['log_time']), |
|
675 |
+ 'member_link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' : (empty($row['real_name']) ? ($this->SFSclass->txt('guest') . (!empty($row['extra']['member_acted']) ? ' (' . $row['extra']['member_acted'] . ')' : '')) : $row['real_name']), |
|
676 |
+ 'username' => $row['username'], |
|
677 |
+ 'email' => $row['email'], |
|
678 |
+ 'ip' => '<a href="' . sprintf($this->urlSFSipCheck, $row['ip']) . '">' . $row['ip'] . '</a>', |
|
679 |
+ 'ip2' => '<a href="' . sprintf($this->urlSFSipCheck, $row['ip2']) . '">' . $row['ip2'] . '</a>', |
|
680 |
+ 'editable' => true, //time() > $row['log_time'] + $this->hoursDisabled * 3600, |
|
681 |
+ 'checks_raw' => $row['checks'], |
|
682 |
+ 'result_raw' => $row['result'], |
|
683 |
+ ); |
|
684 |
+ |
|
685 |
+ $checksDecoded = $this->SFSclass->decodeJSON($row['checks']); |
|
686 |
+ |
|
687 |
+ // If we know what check triggered this, link it up to be searched. |
|
688 |
+ if ($row['id_type'] == 1) |
|
689 |
+ $return['checks'] = '<a href="' . sprintf($this->urlSFSsearch, $checksDecoded['value']) . '">' . $checksDecoded['value'] . '</a>'; |
|
690 |
+ elseif ($row['id_type'] == 2) |
|
691 |
+ $return['checks'] = '<a href="' . sprintf($this->urlSFSsearch, $checksDecoded['value']) . '">' . $checksDecoded['value'] . '</a>'; |
|
692 |
+ elseif ($row['id_type'] == 3) |
|
693 |
+ $return['checks'] = '<a href="' . sprintf($this->urlSFSsearch, $checksDecoded['value']) . '">' . $checksDecoded['value'] . '</a>'; |
|
694 |
+ // No idea what triggered it, parse it out cleanly. Could be debug data as well. |
|
695 |
+ else |
|
696 |
+ { |
|
697 |
+ $return['checks'] = ''; |
|
698 |
+ |
|
699 |
+ foreach ($checksDecoded as $ckey => $vkey) |
|
700 |
+ foreach ($vkey as $key => $value) |
|
701 |
+ $return['checks'] .= ucfirst($key) . ':' . $value . '<br>'; |
|
702 |
+ } |
|
703 |
+ |
|
704 |
+ // This tells us what it matched on exactly. |
|
705 |
+ if (strpos($row['result'], ',') !== false) |
|
706 |
+ { |
|
707 |
+ list($resultType, $resultMatch, $extra) = explode(',', $row['result'] . ',,,'); |
|
708 |
+ $return['result'] = sprintf($this->SFSclass->txt('sfs_log_matched_on'), $resultType, $resultMatch); |
|
709 |
+ |
|
710 |
+ // If this was a IP ban, note it. |
|
711 |
+ if ($resultType == 'ip' && !empty($extra)) |
|
712 |
+ $return['result'] .= ' ' . $this->SFSclass->txt('sfs_log_auto_banned'); |
|
713 |
+ if ($resultType == 'username' && !empty($extra)) |
|
714 |
+ $return['result'] .= ' ' . sprintf($this->SFSclass->txt('sfs_log_confidence'), $extra); |
|
715 |
+ } |
|
716 |
+ else |
|
717 |
+ $return['result'] = $row['result']; |
|
718 |
+ |
|
719 |
+ return $return; |
|
720 |
+ } |
|
721 |
+ |
|
722 |
+ /** |
|
723 |
+ * Get the log counts and returns it ready to go for GenericList handling. |
|
724 |
+ * |
|
725 |
+ * @param string $query_string The search string we are using to filter log data. |
|
726 |
+ * @param array $query_params Extra parameters for searching. |
|
727 |
+ * |
|
728 |
+ * @api |
|
729 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
730 |
+ * @See SFSA::loadLogs |
|
731 |
+ * @version 1.0 |
|
732 |
+ * @since 1.0 |
|
733 |
+ * @uses hook_manage_logs - Hook SMF2.1 |
|
734 |
+ * @uses setupModifyModifications - Injected SMF2.0 |
|
735 |
+ * @return void No return is generated |
|
736 |
+ */ |
|
737 |
+ public function getSFSLogEntriesCount(string $query_string = '', array $query_params = array()): int |
|
738 |
+ { |
|
739 |
+ global $smcFunc, $user_info; |
|
740 |
+ |
|
741 |
+ $result = $smcFunc['db_query']('', ' |
|
742 |
+ SELECT COUNT(*) |
|
743 |
+ FROM {db_prefix}log_sfs AS l |
|
744 |
+ LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = l.id_member) |
|
745 |
+ LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END) |
|
746 |
+ WHERE id_type IS NOT NULL' |
|
747 |
+ . (!empty($query_string) ? ' |
|
748 |
+ AND ' . $query_string : ''), |
|
749 |
+ array_merge($query_params, array( |
|
750 |
+ 'reg_group_id' => 0, |
|
751 |
+ )) |
|
752 |
+ ); |
|
753 |
+ list ($entry_count) = $smcFunc['db_fetch_row']($result); |
|
754 |
+ $smcFunc['db_free_result']($result); |
|
755 |
+ |
|
756 |
+ return (int) $entry_count; |
|
757 |
+ } |
|
758 |
+ |
|
759 |
+ /** |
|
760 |
+ * Remove all logs, except those less than 24 hours old. |
|
761 |
+ * |
|
762 |
+ * @api |
|
763 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
764 |
+ * @See SFSA::loadLogs |
|
765 |
+ * @version 1.0 |
|
766 |
+ * @since 1.0 |
|
767 |
+ * @return void No return is generated |
|
768 |
+ */ |
|
769 |
+ private function removeAllLogs(): void |
|
770 |
+ { |
|
771 |
+ global $smcFunc; |
|
772 |
+ |
|
773 |
+ checkSession(); |
|
774 |
+ |
|
775 |
+ $smcFunc['db_query']('', ' |
|
776 |
+ DELETE FROM {db_prefix}log_sfs |
|
777 |
+ WHERE log_time < {int:twenty_four_hours_wait}', |
|
778 |
+ array( |
|
779 |
+ 'twenty_four_hours_wait' => time() - $this->hoursDisabled * 3600, |
|
780 |
+ ) |
|
781 |
+ ); |
|
782 |
+ } |
|
783 |
+ |
|
784 |
+ /** |
|
785 |
+ * Remove specific logs, except those less than 24 hours old. |
|
786 |
+ * |
|
787 |
+ * @param array $entries A array of the ids that we want to remove. |
|
788 |
+ * |
|
789 |
+ * @api |
|
790 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
791 |
+ * @See SFSA::loadLogs |
|
792 |
+ * @version 1.0 |
|
793 |
+ * @since 1.0 |
|
794 |
+ * @return void No return is generated |
|
795 |
+ */ |
|
796 |
+ private function removeLogs(array $entries): void |
|
797 |
+ { |
|
798 |
+ global $smcFunc; |
|
799 |
+ |
|
800 |
+ checkSession(); |
|
801 |
+ |
|
802 |
+ $smcFunc['db_query']('', ' |
|
803 |
+ DELETE FROM {db_prefix}log_sfs |
|
804 |
+ WHERE id_sfs IN ({array_string:delete_actions}) |
|
805 |
+ AND log_time < {int:twenty_four_hours_wait}', |
|
806 |
+ array( |
|
807 |
+ 'twenty_four_hours_wait' => time() - $this->hoursDisabled * 3600, |
|
808 |
+ 'delete_actions' => $entries, |
|
809 |
+ ) |
|
810 |
+ ); |
|
811 |
+ } |
|
812 |
+ |
|
813 |
+ /** |
|
814 |
+ * Handle searching for logs. |
|
815 |
+ * |
|
816 |
+ * @param string $url The base_href |
|
817 |
+ * @internal |
|
818 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
819 |
+ * @version 1.0 |
|
820 |
+ * @since 1.0 |
|
821 |
+ * @return void No return is generated here. |
|
822 |
+ */ |
|
823 |
+ private function handleLogSearch(string &$url): void |
|
824 |
+ { |
|
825 |
+ global $context, $txt; |
|
826 |
+ |
|
827 |
+ // If we have some data from a search, lets bring it back out. |
|
828 |
+ $this->search_params = $this->handleLogSearchParams(); |
|
829 |
+ |
|
830 |
+ // What we can search. |
|
831 |
+ $this->search_types = $this->handleLogSearchTypes(); |
|
832 |
+ $this->search_params_string = $this->handleLogSearchParamsString(); |
|
833 |
+ $this->search_params_type = $this->handleLogSearchParamsType(); |
|
834 |
+ |
|
835 |
+ $this->search_params_column = $this->search_types[$this->search_params_type]['sql']; |
|
836 |
+ |
|
837 |
+ // Setup the search context. |
|
838 |
+ $this->search_params = empty($this->search_params_string) ? '' : base64_encode(json_encode(array( |
|
839 |
+ 'string' => $this->search_params_string, |
|
840 |
+ 'type' => $this->search_params_type, |
|
841 |
+ ))); |
|
842 |
+ $this->logSearch = array( |
|
843 |
+ 'string' => $this->search_params_string, |
|
844 |
+ 'type' => $this->search_params_type, |
|
845 |
+ 'label' => $this->search_types[$this->search_params_type]['label'], |
|
846 |
+ ); |
|
847 |
+ |
|
848 |
+ if (!empty($this->search_params)) |
|
849 |
+ $url .= ';params=' . $this->search_params; |
|
850 |
+ } |
|
851 |
+ |
|
852 |
+ /** |
|
853 |
+ * Handle Search Params |
|
854 |
+ * |
|
855 |
+ * @internal |
|
856 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
857 |
+ * @version 1.1 |
|
858 |
+ * @since 1.0 |
|
859 |
+ * @return bool True upon success, false otherwise. |
|
860 |
+ */ |
|
861 |
+ private function handleLogSearchParams(): array |
|
862 |
+ { |
|
863 |
+ // If we have something to search for saved, get it back out. |
|
864 |
+ if (!empty($_REQUEST['params']) && empty($_REQUEST['is_search'])) |
|
865 |
+ { |
|
866 |
+ $search_params = base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))); |
|
867 |
+ $search_params = $this->SFSclass->decodeJSON($search_params); |
|
868 |
+ |
|
869 |
+ if (!empty($search_params)) |
|
870 |
+ return $search_params; |
|
871 |
+ } |
|
872 |
+ |
|
873 |
+ return array(); |
|
874 |
+ } |
|
875 |
+ |
|
876 |
+ /** |
|
877 |
+ * Handle Search Types |
|
878 |
+ * |
|
879 |
+ * @internal |
|
880 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
881 |
+ * @version 1.2 |
|
882 |
+ * @since 1.0 |
|
883 |
+ * @return array The valid Search Types. |
|
884 |
+ */ |
|
885 |
+ private function handleLogSearchTypes(): array |
|
886 |
+ { |
|
887 |
+ return array( |
|
888 |
+ 'url' => array('sql' => 'l.url', 'label' => $this->SFSclass->txt('sfs_log_search_url')), |
|
889 |
+ 'member' => array('sql' => 'mem.real_name', 'label' => $this->SFSclass->txt('sfs_log_search_member')), |
|
890 |
+ 'username' => array('sql' => 'l.username', 'label' => $this->SFSclass->txt('sfs_log_search_username')), |
|
891 |
+ 'email' => array('sql' => 'l.email', 'label' => $this->SFSclass->txt('sfs_log_search_email')), |
|
892 |
+ 'ip' => array('sql' => 'lm.ip', 'label' => $this->SFSclass->txt('sfs_log_search_ip')), |
|
893 |
+ 'ip2' => array('sql' => 'lm.ip2', 'label' => $this->SFSclass->txt('sfs_log_search_ip2')) |
|
894 |
+ ); |
|
895 |
+ } |
|
896 |
+ |
|
897 |
+ /** |
|
898 |
+ * Handle Search Params String |
|
899 |
+ * |
|
900 |
+ * @internal |
|
901 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
902 |
+ * @version 1.1 |
|
903 |
+ * @since 1.0 |
|
904 |
+ * @return string What we are searching for, validated and cleaned. |
|
905 |
+ */ |
|
906 |
+ private function handleLogSearchParamsString(): string |
|
907 |
+ { |
|
908 |
+ if (!isset($this->search_params['string']) || (!empty($_REQUEST['search']) && $this->search_params['string'] != $_REQUEST['search'])) |
|
909 |
+ return empty($_REQUEST['search']) ? '' : $_REQUEST['search']; |
|
910 |
+ else |
|
911 |
+ return $this->search_params['string']; |
|
912 |
+ } |
|
913 |
+ |
|
914 |
+ /** |
|
915 |
+ * Handle Search Params Type |
|
916 |
+ * |
|
917 |
+ * @internal |
|
918 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
919 |
+ * @version 1.1 |
|
920 |
+ * @since 1.0 |
|
921 |
+ * @return string The column we are searching. |
|
922 |
+ */ |
|
923 |
+ private function handleLogSearchParamsType(): string |
|
924 |
+ { |
|
925 |
+ global $context; |
|
926 |
+ |
|
927 |
+ if (isset($_REQUEST['search_type']) || empty($this->search_params['type']) || !isset($this->search_types[$this->search_params['type']])) |
|
928 |
+ return isset($_REQUEST['search_type']) && isset($this->search_types[$_REQUEST['search_type']]) ? $_REQUEST['search_type'] : (isset($this->search_types[$context['order']]) ? $context['order'] : 'member'); |
|
929 |
+ return $this->search_params['type']; |
|
930 |
+ } |
|
931 |
+} |
|
0 | 932 |
\ No newline at end of file |
... | ... |
@@ -6,7 +6,7 @@ |
6 | 6 |
* @author SleePy <sleepy @ simplemachines (dot) org> |
7 | 7 |
* @copyright 2019 |
8 | 8 |
* @license 3-Clause BSD https://opensource.org/licenses/BSD-3-Clause |
9 |
- * @version 1.0.1 |
|
9 |
+ * @version 1.2 |
|
10 | 10 |
*/ |
11 | 11 |
class SFS |
12 | 12 |
{ |
... | ... |
@@ -22,6 +22,15 @@ class SFS |
22 | 22 |
private $softwareName = 'smf'; |
23 | 23 |
private $softwareVersion = '2.1'; |
24 | 24 |
|
25 |
+ /** |
|
26 |
+ * @var array The block Types. |
|
27 |
+ */ |
|
28 |
+ private $blockTypeMap = array( |
|
29 |
+ 'username' => 1, |
|
30 |
+ 'email' => 2, |
|
31 |
+ 'ip' => 3 |
|
32 |
+ ); |
|
33 |
+ |
|
25 | 34 |
/** |
26 | 35 |
* Simple setup for the class to be used later correctly. |
27 | 36 |
* This simply loads the class into $smcFunc and we can grab this anywhere else later. |
... | ... |
@@ -144,7 +153,7 @@ class SFS |
144 | 153 |
* |
145 | 154 |
* @api |
146 | 155 |
* @CalledIn SMF 2.0, SMF 2.1 |
147 |
- * @version 1.0 |
|
156 |
+ * @version 1.2 |
|
148 | 157 |
* @since 1.0 |
149 | 158 |
* @uses create_control_verification - Hook SMF2.0 |
150 | 159 |
* @uses integrate_create_control_verification_test - Hook SMF2.1 |
... | ... |
@@ -161,15 +170,16 @@ class SFS |
161 | 170 |
// Get our options data. |
162 | 171 |
$options = $this->getVerificationOptions(); |
163 | 172 |
|
164 |
- // Posting? |
|
165 |
- if ($thisVerification['id'] == 'post' && in_array('post', $options)) |
|
166 |
- return $this->checkVerificationTestPosts(); |
|
167 |
- // reporting topics is only for guests. |
|
168 |
- elseif ($thisVerification['id'] == 'report' && in_array('report', $options)) |
|
169 |
- return $this->checkVerificationTestReport(); |
|
170 |
- // We should avoid this on searches, as we can only send ips. |
|
171 |
- elseif ($thisVerification['id'] == 'search' && in_array('search', $options) && ($user_info['is_guest'] || empty($user_info['posts']) || $user_info['posts'] < $modSettings['sfs_verfOptMemPostThreshold'])) |
|
172 |
- return $this->checkVerificationTestSearch(); |
|
173 |
+ // Key => Extended checks. |
|
174 |
+ $verificationMap = array( |
|
175 |
+ 'post' => true, |
|
176 |
+ 'report' => true, |
|
177 |
+ 'search' => $user_info['is_guest'] || empty($user_info['posts']) || $user_info['posts'] < $modSettings['sfs_verfOptMemPostThreshold'], |
|
178 |
+ ); |
|
179 |
+ |
|
180 |
+ foreach ($verificationMap as $key => $extendedChecks) |
|
181 |
+ if ($thisVerification['id'] == $key && in_array($key, $options)) |
|
182 |
+ return call_user_func($this, 'checkVerificationTest' . ucfirst($key)); |
|
173 | 183 |
|
174 | 184 |
// Others areas. We have to play a guessing game here. |
175 | 185 |
return $this->checkVerificationTestExtra($thisVerification); |
... | ... |
@@ -184,7 +194,7 @@ class SFS |
184 | 194 |
* @since 1.1 |
185 | 195 |
* @return bool True is success, no other bool is expeicifcly defined yet. |
186 | 196 |
*/ |
187 |
- private function checkVerificationTestPosts(): bool |
|
197 |
+ private function checkVerificationTestPost(): bool |
|
188 | 198 |
{ |
189 | 199 |
global $user_info, $modSettings; |
190 | 200 |
|
... | ... |
@@ -312,7 +322,7 @@ class SFS |
312 | 322 |
* |
313 | 323 |
* @internal |
314 | 324 |
* @CalledIn SMF 2.0, SMF 2.1 |
315 |
- * @version 1.0 |
|
325 |
+ * @version 1.2 |
|
316 | 326 |
* @since 1.0 |
317 | 327 |
* @return bool True is success, no other bool is expeicifcly defined yet. |
318 | 328 |
*/ |
... | ... |
@@ -337,20 +347,18 @@ class SFS |
337 | 347 |
$response = $this->sendSFSCheck($requestURL, $checks, $area); |
338 | 348 |
$requestBlocked = ''; |
339 | 349 |
|
340 |
- // Handle IPs only if we are supposed to, this is just a double check. |
|
341 |
- if (!empty($modSettings['sfs_ipcheck']) && !empty($response['ip'])) |
|
342 |
- $requestBlocked = $this->sfsCheck_ips($response['ip']); |
|
343 |
- |
|
344 |
- // If we didn't match a IP, handle Usernames only if we are supposed to, this is just a double check. |
|
345 |
- if (empty($requestBlocked) && !empty($modSettings['sfs_usernamecheck']) && !empty($response['username'])) |
|
346 |
- $requestBlocked = $this->sfsCheck_username($response['username']); |
|
350 |
+ $checkMap = array( |
|
351 |
+ 'ip' => !empty($modSettings['sfs_ipcheck']) && !empty($response['ip']), |
|
352 |
+ 'username' => !empty($modSettings['sfs_usernamecheck']) && !empty($response['username']), |
|
353 |
+ 'email' => !empty($modSettings['sfs_emailcheck']) && !empty($response['email']) |
|
354 |
+ ); |
|
347 | 355 |
|
348 |
- // If we didn't match a IP or username, handle Emails only if we are supposed to, this is just a double check. |
|
349 |
- if (empty($requestBlocked) && !empty($modSettings['sfs_emailcheck']) && !empty($response['email'])) |
|
350 |
- $requestBlocked = $this->sfsCheck_email($response['email']); |
|
356 |
+ // Run all the checks, if we should. |
|
357 |
+ foreach ($checkMap as $key => $checkEnabled) |
|
358 |
+ if (empty($requestBlocked) && $checkEnabled) |
|
359 |
+ $requestBlocked = call_user_func(array($this, 'sfsCheck_' . $key), $response[$key], $area); |
|
351 | 360 |
|
352 | 361 |
// Log all the stats? Debug mode here. |
353 |
- if (!empty($modSettings['sfs_log_debug'])) |
|
354 | 362 |
$this->logAllStats('all', $checks, $requestBlocked); |
355 | 363 |
|
356 | 364 |
// At this point, we have checked everything, do what needs to be done for our good person. |
... | ... |
@@ -370,7 +378,7 @@ class SFS |
370 | 378 |
* |
371 | 379 |
* @internal |
372 | 380 |
* @CalledIn SMF 2.0, SMF 2.1 |
373 |
- * @version 1.1 |
|
381 |
+ * @version 1.2 |
|
374 | 382 |
* @since 1.1 |
375 | 383 |
* @return array data we received back, could be a empty array. |
376 | 384 |
*/ |
... | ... |
@@ -411,11 +419,11 @@ class SFS |
411 | 419 |
* @param string $area If defined the area we are checking. |
412 | 420 |
* @internal |
413 | 421 |
* @CalledIn SMF 2.0, SMF 2.1 |
414 |
- * @version 1.1 |
|
422 |
+ * @version 1.2 |
|
415 | 423 |
* @since 1.1 |
416 | 424 |
* @return string Request Blocked data if any |
417 | 425 |
*/ |
418 |
- private function sfsCheck_ips(array $ips, string $area = ''): string |
|
426 |
+ private function sfsCheck_ip(array $ips, string $area = ''): string |
|
419 | 427 |
{ |
420 | 428 |
global $modSettings, $smcFunc; |
421 | 429 |
|
... | ... |
@@ -423,8 +431,9 @@ class SFS |
423 | 431 |
foreach ($ips as $check) |
424 | 432 |
{ |
425 | 433 |
// They appeared! Block this. |
426 |
- if (!empty($check['appears'])) |
|
427 |
- { |
|
434 |
+ if (empty($check['appears'])) |
|
435 |
+ continue; |
|
436 |
+ |
|
428 | 437 |
// Ban them because they are black listed? |
429 | 438 |
$autoBlackListResult = '0'; |
430 | 439 |
if (!empty($modSettings['sfs_ipcheck_autoban']) && !empty($check['frequency']) && $check['frequency'] == 255) |
... | ... |
@@ -434,7 +443,6 @@ class SFS |
434 | 443 |
$requestBlocked = 'ip,' . $smcFunc['htmlspecialchars']($check['value']) . ',' . ($autoBlackListResult ? 1 : 0); |
435 | 444 |
break; |
436 | 445 |
} |
437 |
- } |
|
438 | 446 |
|
439 | 447 |
return $requestBlocked; |
440 | 448 |
} |
... | ... |
@@ -446,7 +454,7 @@ class SFS |
446 | 454 |
* @param string $area If defined the area we are checking. |
447 | 455 |
* @internal |
448 | 456 |
* @CalledIn SMF 2.0, SMF 2.1 |
449 |
- * @version 1.1 |
|
457 |
+ * @version 1.2 |
|
450 | 458 |
* @since 1.1 |
451 | 459 |
* @return string Request Blocked data if any |
452 | 460 |
*/ |
... | ... |
@@ -458,21 +466,15 @@ class SFS |
458 | 466 |
foreach ($usernames as $check) |
459 | 467 |
{ |
460 | 468 |
// Combine with $area we could also require admin approval above thresholds on things like register. |
461 |
- if (!empty($check['appears'])) |
|
462 |
- { |
|
469 |
+ if (empty($check['appears'])) |
|
470 |
+ continue; |
|
471 |
+ |
|
463 | 472 |
$shouldBlock = true; |
464 |
- $confidenceLevel = 0; |
|
465 | 473 |
|
466 |
- // They meet the confidence level, block them. |
|
467 |
- if (!empty($modSettings['sfs_username_confidence']) && !empty($check['confidence']) && $area == 'register' && (float) $modSettings['sfs_username_confidence'] <= (float) $check['confidence']) |
|
468 |
- $confidenceLevel = $check['confidence']; |
|
469 | 474 |
// We are not confident that they should be blocked. |
470 | 475 |
if (!empty($modSettings['sfs_username_confidence']) && !empty($check['confidence']) && $area == 'register' && (float) $modSettings['sfs_username_confidence'] > (float) $check['confidence']) |
471 | 476 |
{ |
472 |
- // Incase we need to debug this. |
|
473 |
- if (!empty($modSettings['sfs_log_debug'])) |
|
474 | 477 |
$this->logAllStats('all', $check, 'username,' . $smcFunc['htmlspecialchars']($check['value']) . ',' . $check['confidence']); |
475 |
- |
|
476 | 478 |
$shouldBlock = false; |
477 | 479 |
} |
478 | 480 |
|
... | ... |
@@ -480,11 +482,10 @@ class SFS |
480 | 482 |
if ($shouldBlock) |
481 | 483 |
{ |
482 | 484 |
$this->logBlockedStats('username', $check); |
483 |
- $requestBlocked = 'username,' . $smcFunc['htmlspecialchars']($check['value']) . ',' . $confidenceLevel; |
|
485 |
+ $requestBlocked = 'username,' . $smcFunc['htmlspecialchars']($check['value']) . ',' . $check['confidence']; |
|
484 | 486 |
break; |
485 | 487 |
} |
486 | 488 |
} |
487 |
- } |
|
488 | 489 |
|
489 | 490 |
return $requestBlocked; |
490 | 491 |
} |
... | ... |
@@ -496,7 +497,7 @@ class SFS |
496 | 497 |
* @param string $area If defined the area we are checking. |
497 | 498 |
* @internal |
498 | 499 |
* @CalledIn SMF 2.0, SMF 2.1 |
499 |
- * @version 1.1 |
|
500 |
+ * @version 1.2 |
|
500 | 501 |
* @since 1.1 |
501 | 502 |
* @return string Request Blocked data if any |
502 | 503 |
*/ |
... | ... |
@@ -507,13 +508,13 @@ class SFS |
507 | 508 |
$requestBlocked = ''; |
508 | 509 |
foreach ($email as $check) |
509 | 510 |
{ |
510 |
- if (!empty($check['appears'])) |
|
511 |
- { |
|
511 |
+ if (empty($check['appears'])) |
|
512 |
+ continue; |
|
513 |
+ |
|
512 | 514 |
$this->logBlockedStats('email', $check); |
513 | 515 |
$requestBlocked = 'email,' . $smcFunc['htmlspecialchars']($check['value']); |
514 | 516 |
break; |
515 | 517 |
} |
516 |
- } |
|
517 | 518 |
|
518 | 519 |
return $requestBlocked; |
519 | 520 |
} |
... | ... |
@@ -527,7 +528,7 @@ class SFS |
527 | 528 |
* |
528 | 529 |
* @internal |
529 | 530 |
* @CalledIn SMF 2.0, SMF 2.1 |
530 |
- * @version 1.0 |
|
531 |
+ * @version 1.2 |
|
531 | 532 |
* @since 1.0 |
532 | 533 |
* @return bool True we found something to check, false nothing.. $requestURL will be updated with the new data. |
533 | 534 |
*/ |
... | ... |
@@ -541,11 +542,7 @@ class SFS |
541 | 542 |
foreach ($chk as $type => $value) |
542 | 543 |
{ |
543 | 544 |
// Hold up, we are not processing this check. |
544 |
- if ( |
|
545 |
- ($type == 'email' && empty($modSettings['sfs_emailcheck'])) || |
|
546 |
- ($type == 'username' && empty($modSettings['sfs_usernamecheck'])) || |
|
547 |
- ($type == 'ip' && empty($modSettings['sfs_ipcheck'])) |
|
548 |
- ) |
|
545 |
+ if (in_array($type, array('email', 'username', 'ip')) && empty($modSettings['sfs_' . $type . 'check'])) |
|
549 | 546 |
continue; |
550 | 547 |
|
551 | 548 |
// No value? Can't do this. |
... | ... |
@@ -582,21 +579,7 @@ class SFS |
582 | 579 |
global $smcFunc, $user_info; |
583 | 580 |
|
584 | 581 |
// What type of log is this? |
585 |
- switch ($type) |
|
586 |
- { |
|
587 |
- case 'username': |
|
588 |
- $blockType = 1; |
|
589 |
- break; |
|
590 |
- case 'email': |
|
591 |
- $blockType = 2; |
|
592 |
- break; |
|
593 |
- case 'ip': |
|
594 |
- $blockType = 3; |
|
595 |
- break; |
|
596 |
- default: |
|
597 |
- $blockType = 99; |
|
598 |
- break; |
|
599 |
- } |
|
582 |
+ $blockType = isset($this->blockTypeMap[$type]) ? $this->blockTypeMap[$type] : 99; |
|
600 | 583 |
|
601 | 584 |
$smcFunc['db_insert']('', |
602 | 585 |
'{db_prefix}log_sfs', |
... | ... |
@@ -637,13 +620,16 @@ class SFS |
637 | 620 |
* |
638 | 621 |
* @internal |
639 | 622 |
* @CalledIn SMF 2.0, SMF 2.1 |
640 |
- * @version 1.0 |
|
623 |
+ * @version 1.2 |
|
641 | 624 |
* @since 1.0 |
642 | 625 |
* @return bool True is success, no other bool is expeicifcly defined yet. |
643 | 626 |
*/ |
644 | 627 |
private function logAllStats(string $type, array $checks, string $DebugMessage): void |
645 | 628 |
{ |
646 |
- global $smcFunc, $user_info; |
|
629 |
+ global $modSettings, $smcFunc, $user_info; |
|
630 |
+ |
|
631 |
+ if ($type == 'all' && empty($modSettings['sfs_log_debug'])) |
|
632 |
+ return; |
|
647 | 633 |
|
648 | 634 |
$smcFunc['db_insert']('', |
649 | 635 |
'{db_prefix}log_sfs', |
... | ... |
@@ -713,7 +699,7 @@ class SFS |
713 | 699 |
* @internal |
714 | 700 |
* @link: https://www.stopforumspam.com/usage |
715 | 701 |
* @CalledIn SMF 2.0, SMF 2.1 |
716 |
- * @version 1.0 |
|
702 |
+ * @version 1.2 |
|
717 | 703 |
* @since 1.0 |
718 | 704 |
* @return array The parsed json string is now an array. |
719 | 705 |
*/ |
... | ... |
@@ -727,39 +713,35 @@ class SFS |
727 | 713 |
return $url; |
728 | 714 |
|
729 | 715 |
// Get our server info. |
730 |
- $this_server = $this->sfsServerMapping(); |
|
731 |
- $server = $this_server[$modSettings['sfs_region']]; |
|
716 |
+ $server = $this->sfsServerMapping()[$modSettings['sfs_region']]; |
|
732 | 717 |
|
733 | 718 |
// Build the base URL, we always use json responses. |
734 | 719 |
$url = 'https://' . $server['host'] . '/api?json'; |
735 | 720 |
|
736 |
- // Ignore all wildcard checks? |
|
737 |
- if (!empty($modSettings['sfs_wildcard_email']) && !empty($modSettings['sfs_wildcard_username']) && !empty($modSettings['sfs_wildcard_ip'])) |
|
738 |
- $url .= '&nobadall'; |
|
721 |
+ // All the SFS Urls => How we toggle them. |
|
722 |
+ $sfsMap = array( |
|
723 |
+ 'nobadall' => !empty($modSettings['sfs_wildcard_email']) && !empty($modSettings['sfs_wildcard_username']) && !empty($modSettings['sfs_wildcard_ip']), |
|
724 |
+ 'notorexit' => !empty($modSettings['sfs_tor_check']) && $modSettings['sfs_tor_check'] == 1, |
|
725 |
+ 'badtorexit' => !empty($modSettings['sfs_tor_check']) && $modSettings['sfs_tor_check'] == 2, |
|
726 |
+ ); |
|
727 |
+ foreach ($sfsMap as $val => $key) |
|
728 |
+ if (!empty($key)) |
|
729 |
+ $url .= '&' . $val; |
|
730 |
+ |
|
739 | 731 |
// Maybe only certain wildcards are ignored? |
740 |
- else |
|
732 |
+ if (empty($sfsMap['nobadall'])) |
|
741 | 733 |
{ |
742 |
- // Ignoring Wildcard Emails? |
|
743 |
- if (!empty($modSettings['sfs_wildcard_email'])) |
|
744 |
- $url .= '&nobadusername'; |
|
745 |
- |
|
746 |
- // Ignoring Wildcard Usernames? |
|
747 |
- if (!empty($modSettings['sfs_wildcard_username'])) |
|
748 |
- $url .= '&nobademail'; |
|
734 |
+ $ignoreMap = array( |
|
735 |
+ 'nobadusername' => !empty($modSettings['sfs_wildcard_email']), |
|
736 |
+ 'nobademail' => !empty($modSettings['sfs_wildcard_username']), |
|
737 |
+ 'nobadip' => !empty($modSettings['sfs_wildcard_ip']), |
|
738 |
+ ); |
|
749 | 739 |
|
750 |
- // Ignoring Wildcard IPs? |
|
751 |
- if (!empty($modSettings['sfs_wildcard_ip'])) |
|
752 |
- $url .= '&nobadip'; |
|
740 |
+ foreach ($ignoreMap as $val => $key) |
|
741 |
+ if (!empty($key)) |
|
742 |
+ $url .= '&' . $val; |
|
753 | 743 |
} |
754 | 744 |
|
755 |
- // Tor handling, ignore them all. Not recommended... |
|
756 |
- if (!empty($modSettings['sfs_tor_check']) && $modSettings['sfs_tor_check'] == 1) |
|
757 |
- $url .= '¬orexit'; |
|
758 |
- // Only block bad exit nodes. |
|
759 |
- elseif (!empty($modSettings['sfs_tor_check']) && $modSettings['sfs_tor_check'] == 2) |
|
760 |
- $url .= '&badtorexit'; |
|
761 |
- // Default handling for Tor is to block all exit nodes, nothing needed here. |
|
762 |
- |
|
763 | 745 |
// Do we have to filter out from lastseen? |
764 | 746 |
if (!empty($modSettings['sfs_expire'])) |
765 | 747 |
$url .= '&expire=' . (int) $modSettings['sfs_expire']; |
... | ... |
@@ -819,7 +801,7 @@ class SFS |
819 | 801 |
* @since 1.0 |
820 | 802 |
* @return array The list of servers. |
821 | 803 |
*/ |
822 |
- private function getVerificationOptions() |
|
804 |
+ private function getVerificationOptions(): array |
|
823 | 805 |
{ |
824 | 806 |
global $user_info, $modSettings; |
825 | 807 |
|
... | ... |
@@ -827,19 +809,18 @@ class SFS |
827 | 809 |
$optionsKeyExtra = $user_info['is_guest'] ? 'sfs_verification_options_extra' : 'sfs_verOptionsMemExtra'; |
828 | 810 |
|
829 | 811 |
// Standard options. |
812 |
+ $options = array(); |
|
830 | 813 |
if ($this->versionCheck('2.0', 'smf') && !empty($modSettings[$optionsKey])) |
831 | 814 |
$options = safe_unserialize($modSettings[$optionsKey]); |
832 | 815 |
elseif (!empty($modSettings[$optionsKey])) |
833 | 816 |
$options = $this->decodeJSON($modSettings[$optionsKey]); |
834 |
- else |
|
835 |
- $options = array(); |
|
836 | 817 |
|
837 | 818 |
// Extras. |
838 | 819 |
if (!empty($modSettings[$optionsKeyExtra])) |
839 | 820 |
{ |
840 | 821 |
$this->extraVerificationOptions = explode(',', $modSettings[$optionsKeyExtra]); |
841 | 822 |
|
842 |
- if (is_array($options) && !empty($this->extraVerificationOptions)) |
|
823 |
+ if (!empty($this->extraVerificationOptions)) |
|
843 | 824 |
$options = array_merge($options, $this->extraVerificationOptions); |
844 | 825 |
} |
845 | 826 |
|
... | ... |
@@ -873,10 +854,11 @@ class SFS |
873 | 854 |
); |
874 | 855 |
|
875 | 856 |
// SMF 2.0 is serialized, SMF 2.1 is json. |
857 |
+ $encodeFunc = 'json_encode'; |
|
876 | 858 |
if ($this->versionCheck('2.0', 'smf')) |
877 |
- $defaultSettings['sfs_verification_options'] = serialize(array('post')); |
|
878 |
- else |
|
879 |
- $defaultSettings['sfs_verification_options'] = json_encode(array('post')); |
|
859 |
+ $encodeFunc = 'serialize'; |
|
860 |
+ |
|
861 |
+ $defaultSettings['sfs_verification_options'] = $encodeFunc(array('post')); |
|
880 | 862 |
|
881 | 863 |
// We undoing this? Maybe a save? |
882 | 864 |
if ($undo) |
... | ... |
@@ -985,7 +967,7 @@ class SFS |
985 | 967 |
* |
986 | 968 |
* @internal |
987 | 969 |
* @CalledIn SMF 2.0, SMF 2.1 |
988 |
- * @version 1.1 |
|
970 |
+ * @version 1.2 |
|
989 | 971 |
* @since 1.0 |
990 | 972 |
* @return bool True upon success, false otherwise. |
991 | 973 |
*/ |
... | ... |
@@ -1043,7 +1025,31 @@ class SFS |
1043 | 1025 |
|
1044 | 1026 |
// Fall back. |
1045 | 1027 |
if (is_array($ban_group_id) || empty($ban_group_id)) |
1028 |
+ $ban_group_id = $this->createBanGroupDirect($ban_info); |
|
1029 |
+ |
|
1030 |
+ // Didn't work? Try again later. |
|
1031 |
+ if (empty($ban_group_id)) |
|
1032 |
+ return false; |
|
1033 |
+ |
|
1034 |
+ updateSettings(array('sfs_ipcheck_autoban_group' => $ban_group_id)); |
|
1035 |
+ return true; |
|
1036 |
+ } |
|
1037 |
+ |
|
1038 |
+ /** |
|
1039 |
+ * We failed to create a ban group via the API, do it manually. |
|
1040 |
+ * |
|
1041 |
+ * @param array $ban_info The ban info |
|
1042 |
+ * |
|
1043 |
+ * @internal |
|
1044 |
+ * @CalledIn SMF 2.0, SMF 2.1 |
|
1045 |
+ * @version 1.2 |
|
1046 |
+ * @since 1.2 |
|
1047 |
+ * @return bool True upon success, false otherwise. |
|
1048 |
+ */ |
|
1049 |
+ public function createBanGroupDirect(array $ban_info): int |
|
1046 | 1050 |
{ |
1051 |
+ global $smcFunc; |
|
1052 |
+ |
|
1047 | 1053 |
$smcFunc['db_insert']('', |
1048 | 1054 |
'{db_prefix}ban_groups', |
1049 | 1055 |
array( |
... | ... |
@@ -1057,15 +1063,7 @@ class SFS |
1057 | 1063 |
array('id_ban_group'), |
1058 | 1064 |
1 |
1059 | 1065 |
); |
1060 |
- $ban_group_id = $smcFunc['db_insert_id']('{db_prefix}ban_groups', 'id_ban_group'); |
|
1061 |
- } |
|
1062 |
- |
|
1063 |
- // Didn't work? Try again later. |
|
1064 |
- if (empty($ban_group_id)) |
|
1065 |
- return false; |
|
1066 |
- |
|
1067 |
- updateSettings(array('sfs_ipcheck_autoban_group' => $ban_group_id)); |
|
1068 |
- return true; |
|
1066 |
+ return $smcFunc['db_insert_id']('{db_prefix}ban_groups', 'id_ban_group'); |
|
1069 | 1067 |
} |
1070 | 1068 |
|
1071 | 1069 |
/** |
... | ... |
@@ -1076,7 +1074,7 @@ class SFS |
1076 | 1074 |
* |
1077 | 1075 |
* @internal |
1078 | 1076 |
* @CalledIn SMF 2.0, SMF 2.1 |
1079 |
- * @version 1.1 |
|
1077 |
+ * @version 1.2 |
|
1080 | 1078 |
* @since 1.0 |
1081 | 1079 |
* @return bool True upon success, false otherwise. |
1082 | 1080 |
*/ |
... | ... |
@@ -1084,23 +1082,56 @@ class SFS |
1084 | 1082 |
{ |
1085 | 1083 |
global $smcFunc, $modSettings, $sourcedir; |
1086 | 1084 |
|
1087 |
- // Is this disabled? Don't do it. |
|
1088 |
- if (empty($modSettings['sfs_ipcheck_autoban'])) |
|
1089 |
- return false; |
|
1090 |
- |
|
1091 | 1085 |
// Did we loose our Ban Group? Try to fix this. |
1092 |
- if (empty($modSettings['sfs_ipcheck_autoban_group'])) |
|
1086 |
+ if (!empty($modSettings['sfs_ipcheck_autoban']) && empty($modSettings['sfs_ipcheck_autoban_group'])) |
|
1093 | 1087 |
$this->createBanGroup(); |
1094 | 1088 |
|
1095 | 1089 |
// Still no Ban Group? Bail out. |
1096 |
- if (empty($modSettings['sfs_ipcheck_autoban_group'])) |
|
1090 |
+ if (empty($modSettings['sfs_ipcheck_autoban']) || empty($modSettings['sfs_ipcheck_autoban_group'])) |
|
1097 | 1091 |
return false; |
1098 | 1092 |
|
1099 | 1093 |
require_once($sourcedir . '/ManageBans.php'); |
1100 | 1094 |
|
1101 | 1095 |
// If we have it, use the standard function. |
1102 |
- if (function_exists('insertBanGroup')) |
|
1096 |
+ if (function_exists('addTriggers')) |
|
1097 |
+ $result = $this->BanNewIPSMF21($ip_address); |
|
1098 |
+ // Go old school. |
|
1099 |
+ else |
|
1100 |
+ $result = $this->BanNewIPSMF20($ip_address); |
|
1101 |
+ |
|
1102 |
+ // Did this work? |
|
1103 |
+ if ($result) |
|
1104 |
+ { |
|
1105 |
+ // Log this. The log will show from the user/guest and ip of spammer. |
|
1106 |
+ logAction('ban', array( |
|
1107 |
+ 'ip_range' => $ip_address, |
|
1108 |
+ 'new' => 1, |
|
1109 |
+ 'source' => 'sfs' |
|
1110 |
+ )); |
|
1111 |
+ |
|
1112 |
+ // Let things know we need updated ban data. |
|
1113 |
+ updateSettings(array('banLastUpdated' => time())); |
|
1114 |
+ updateBanMembers(); |
|
1115 |
+ } |
|
1116 |
+ |
|
1117 |
+ return true; |
|
1118 |
+ } |
|
1119 |
+ |
|
1120 |
+ /** |
|
1121 |
+ * Ban a IP with using some functions that exist in SMF 2.1. |
|
1122 |
+ * |
|
1123 |
+ * @param string $ip_address The IP address of the spammer. |
|
1124 |
+ * |
|
1125 |
+ * @internal |
|
1126 |
+ * @CalledIn SMF 2.0 |
|
1127 |
+ * @version 1.2 |
|
1128 |
+ * @since 1.2 |
|
1129 |
+ * @return bool True upon success, false otherwise. |
|
1130 |
+ */ |
|
1131 |
+ private function BanNewIPSMF21(string $ip_address): bool |
|
1103 | 1132 |
{ |
1133 |
+ global $smcFunc, $modSettings; |
|
1134 |
+ |
|
1104 | 1135 |
// We don't call checkExistingTriggerIP as it induces a fatal error. |
1105 | 1136 |
$request = $smcFunc['db_query']('', ' |
1106 | 1137 |
SELECT bg.id_ban_group, bg.name |
... | ... |
@@ -1131,10 +1162,25 @@ class SFS |
1131 | 1162 |
|
1132 | 1163 |
// Add it. |
1133 | 1164 |
addTriggers($modSettings['sfs_ipcheck_autoban_group'], $triggers); |
1165 |
+ |
|
1166 |
+ return true; |
|
1134 | 1167 |
} |
1135 |
- // Go old school. |
|
1136 |
- else |
|
1168 |
+ |
|
1169 |
+ /** |
|
1170 |
+ * We need to fall back to standard db inserts to ban a user as the functions don't exist. |
|
1171 |
+ * |
|
1172 |
+ * @param string $ip_address The IP address of the spammer. |
|
1173 |
+ * |
|
1174 |
+ * @internal |
|
1175 |
+ * @CalledIn SMF 2.0 |
|
1176 |
+ * @version 1.2 |
|
1177 |
+ * @since 1.2 |
|
1178 |
+ * @return bool True upon success, false otherwise. |
|
1179 |
+ */ |
|
1180 |
+ private function BanNewIPSMF20(string $ip_address): bool |
|
1137 | 1181 |
{ |
1182 |
+ global $smcFunc, $modSettings; |
|
1183 |
+ |
|
1138 | 1184 |
$ip_parts = ip2range($ip_address); |
1139 | 1185 |
|
1140 | 1186 |
// Not valid? Get out. |
... | ... |
@@ -1195,18 +1241,6 @@ class SFS |
1195 | 1241 |
$ban_triggers, |
1196 | 1242 |
array('id_ban') |
1197 | 1243 |
); |
1198 |
- } |
|
1199 |
- |
|
1200 |
- // Log this. The log will show from the user/guest and ip of spammer. |
|
1201 |
- logAction('ban', array( |
|
1202 |
- 'ip_range' => $ip_address, |
|
1203 |
- 'new' => 1, |
|
1204 |
- 'source' => 'sfs' |
|
1205 |
- )); |
|
1206 |
- |
|
1207 |
- // Let things know we need updated ban data. |
|
1208 |
- updateSettings(array('banLastUpdated' => time())); |
|
1209 |
- updateBanMembers(); |
|
1210 | 1244 |
|
1211 | 1245 |
return true; |
1212 | 1246 |
} |
... | ... |
@@ -1218,8 +1252,8 @@ class SFS |
1218 | 1252 |
* |
1219 | 1253 |
* @internal |
1220 | 1254 |
* @CalledIn SMF 2.0, SMF 2.1 |
1221 |
- * @version 1.1 |
|
1222 |
- * @since 1.0 |
|
1255 |
+ * @version 1.2 |
|
1256 |
+ * @since 1.2 |
|
1223 | 1257 |
* @return bool True upon success, false otherwise. |
1224 | 1258 |
*/ |
1225 | 1259 |
public function get(string $variable) |
... | ... |
@@ -52,71 +52,160 @@ $smcFunc['db_create_table']($table['table_name'], $table['columns'], $table['ind |
52 | 52 |
/* |
53 | 53 |
* Calculates the proper settings to use in a column. |
54 | 54 |
* |
55 |
+ * @version 1.2 |
|
55 | 56 |
* @since 1.0 |
56 | 57 |
*/ |
57 | 58 |
function db_field($name, $type, $size = 0, $unsigned = true, $auto = false) |
58 | 59 |
{ |
59 | 60 |
$fields = array( |
60 |
- 'varchar' => array( |
|
61 |
+ 'varchar' => db_field_varchar($size, $unsigned, $auto), |
|
62 |
+ 'text' => db_field_text($size, $unsigned, $auto), |
|
63 |
+ 'mediumtext' => db_field_mediumtext($size, $unsigned, $auto), |
|
64 |
+ 'tinyint' => db_field_tinyint($size, $unsigned, $auto), |
|
65 |
+ 'smallint' => db_field_smallint($size, $unsigned, $auto), |
|
66 |
+ 'mediumint' => db_field_mediumint($size, $unsigned, $auto), |
|
67 |
+ 'int' => db_field_int($size, $unsigned, $auto), |
|
68 |
+ 'bigint' => db_field_bigint($size, $unsigned, $auto), |
|
69 |
+ ); |
|
70 |
+ |
|
71 |
+ $field = $fields[$type]; |
|
72 |
+ $field['name'] = $name; |
|
73 |
+ |
|
74 |
+ return $field; |
|
75 |
+} |
|
76 |
+ |
|
77 |
+/* |
|
78 |
+ * Database Field - varchar. |
|
79 |
+ * |
|
80 |
+ * @version 1.2 |
|
81 |
+ * @since 1.2 |
|
82 |
+*/ |
|
83 |
+function db_field_varchar($size = 0, $unsigned = true, $auto = false) |
|
84 |
+{ |
|
85 |
+ return array( |
|
61 | 86 |
'auto' => false, |
62 | 87 |
'type' => 'varchar', |
63 | 88 |
'size' => $size == 0 ? 50 : $size, |
64 | 89 |
'null' => false, |
65 |
- ), |
|
66 |
- 'text' => array( |
|
90 |
+ ); |
|
91 |
+} |
|
92 |
+ |
|
93 |
+/* |
|
94 |
+ * Database Field - text. |
|
95 |
+ * |
|
96 |
+ * @version 1.2 |
|
97 |
+ * @since 1.2 |
|
98 |
+*/ |
|
99 |
+function db_field_text($size = 0, $unsigned = true, $auto = false) |
|
100 |
+{ |
|
101 |
+ return array( |
|
67 | 102 |
'auto' => false, |
68 | 103 |
'type' => 'text', |
69 | 104 |
'null' => false, |
70 |
- ), |
|
71 |
- 'mediumtext' => array( |
|
105 |
+ ); |
|
106 |
+} |
|
107 |
+ |
|
108 |
+/* |
|
109 |
+ * Database Field - mediumtext. |
|
110 |
+ * |
|
111 |
+ * @version 1.2 |
|
112 |
+ * @since 1.2 |
|
113 |
+*/ |
|
114 |
+function db_field_mediumtext($size = 0, $unsigned = true, $auto = false) |
|
115 |
+{ |
|
116 |
+ return array( |
|
72 | 117 |
'auto' => false, |
73 | 118 |
'type' => 'mediumtext', |
74 | 119 |
'null' => false, |
75 |
- ), |
|
76 |
- 'tinyint' => array( |
|
120 |
+ ); |
|
121 |
+} |
|
122 |
+ |
|
123 |
+/* |
|
124 |
+ * Database Field - tinyint. |
|
125 |
+ * |
|
126 |
+ * @version 1.2 |
|
127 |
+ * @since 1.2 |
|
128 |
+*/ |
|
129 |
+function db_field_tinyint($size = 0, $unsigned = true, $auto = false) |
|
130 |
+{ |
|
131 |
+ return array( |
|
77 | 132 |
'auto' => $auto, |
78 | 133 |
'type' => 'tinyint', |
79 | 134 |
'default' => 0, |
80 | 135 |
'size' => empty($unsigned) ? 4 : 3, |
81 | 136 |
'unsigned' => $unsigned, |
82 | 137 |
'null' => false, |
83 |
- ), |
|
84 |
- 'smallint' => array( |
|
138 |
+ ); |
|
139 |
+} |
|
140 |
+ |
|
141 |
+/* |
|
142 |
+ * Database Field - small int. |
|
143 |
+ * |
|
144 |
+ * @version 1.2 |
|
145 |
+ * @since 1.2 |
|
146 |
+*/ |
|
147 |
+function db_field_smallint($size = 0, $unsigned = true, $auto = false) |
|
148 |
+{ |
|
149 |
+ return array( |
|
85 | 150 |
'auto' => $auto, |
86 | 151 |
'type' => 'smallint', |
87 | 152 |
'default' => 0, |
88 | 153 |
'size' => empty($unsigned) ? 6 : 5, |
89 | 154 |
'unsigned' => $unsigned, |
90 | 155 |
'null' => false, |
91 |
- ), |
|
92 |
- 'mediumint' => array( |
|
156 |
+ ); |
|
157 |
+} |
|
158 |
+ |
|
159 |
+/* |
|
160 |
+ * Database Field - mediumn int. |
|
161 |
+ * |
|
162 |
+ * @version 1.2 |
|
163 |
+ * @since 1.2 |
|
164 |
+*/ |
|
165 |
+function db_field_mediumint($size = 0, $unsigned = true, $auto = false) |
|
166 |
+{ |
|
167 |
+ return array( |
|
93 | 168 |
'auto' => $auto, |
94 | 169 |
'type' => 'mediumint', |
95 | 170 |
'default' => 0, |
96 | 171 |
'size' => 8, |
97 | 172 |
'unsigned' => $unsigned, |
98 | 173 |
'null' => false, |
99 |
- ), |
|
100 |
- 'int' => array( |
|
174 |
+ ); |
|
175 |
+} |
|
176 |
+ |
|
177 |
+/* |
|
178 |
+ * Database Field - int. |
|
179 |
+ * |
|
180 |
+ * @version 1.2 |
|
181 |
+ * @since 1.2 |
|
182 |
+*/ |
|
183 |
+function db_field_int($size = 0, $unsigned = true, $auto = false) |
|
184 |
+{ |
|
185 |
+ return array( |
|
101 | 186 |
'auto' => $auto, |
102 | 187 |
'type' => 'int', |
103 | 188 |
'default' => 0, |
104 | 189 |
'size' => empty($unsigned) ? 11 : 10, |
105 | 190 |
'unsigned' => $unsigned, |
106 | 191 |
'null' => false, |
107 |
- ), |
|
108 |
- 'bigint' => array( |
|
192 |
+ ); |
|
193 |
+} |
|
194 |
+ |
|
195 |
+/* |
|
196 |
+ * Database Field - big int. |
|
197 |
+ * |
|
198 |
+ * @version 1.2 |
|
199 |
+ * @since 1.2 |
|
200 |
+*/ |
|
201 |
+function db_field_bigint($size = 0, $unsigned = true, $auto = false) |
|
202 |
+{ |
|
203 |
+ return array( |
|
109 | 204 |
'auto' => $auto, |
110 | 205 |
'type' => 'bigint', |
111 | 206 |
'default' => 0, |
112 | 207 |
'size' => 21, |
113 | 208 |
'unsigned' => $unsigned, |
114 | 209 |
'null' => false, |
115 |
- ), |
|
116 | 210 |
); |
117 |
- |
|
118 |
- $field = $fields[$type]; |
|
119 |
- $field['name'] = $name; |
|
120 |
- |
|
121 |
- return $field; |
|
122 | 211 |
} |
123 | 212 |
\ No newline at end of file |
... | ... |
@@ -40,17 +40,19 @@ |
40 | 40 |
<database>install_sfs.php</database> |
41 | 41 |
|
42 | 42 |
<require-file name="language/StopForumSpam.english.php" destination="$themes_dir/default/languages" /> |
43 |
- <require-file name="StopForumSpam.php" destination="$sourcedir" /> |
|
43 |
+ <require-file name="SFS.php" destination="$sourcedir" /> |
|
44 |
+ <require-file name="SFS-Subs-Admin.php" destination="$sourcedir" /> |
|
45 |
+ <require-file name="SFS-Subs-Logs.php" destination="$sourcedir" /> |
|
44 | 46 |
|
45 | 47 |
<!-- All the hooks --> |
46 | 48 |
<!-- Main Section --> |
47 |
- <hook hook="integrate_pre_include" function="$sourcedir/StopForumSpam.php" /> |
|
49 |
+ <hook hook="integrate_pre_include" function="$sourcedir/SFS.php" /> |
|
48 | 50 |
<hook hook="integrate_pre_load" function="SFS::hook_pre_load" /> |
49 | 51 |
<hook hook="integrate_register" function="SFS::hook_register" /> |
50 | 52 |
<hook hook="integrate_create_control_verification_test" function="SFS::hook_create_control_verification_test" /> |
51 | 53 |
|
52 | 54 |
<!-- Admin Section --> |
53 |
- <hook hook="integrate_admin_include" function="$sourcedir/StopForumSpamAdmin.php" /> |
|
55 |
+ <hook hook="integrate_admin_include" function="$sourcedir/SFS-Subs-Admin.php" /> |
|
54 | 56 |
<hook hook="integrate_admin_areas" function="SFSA::hook_admin_areas" /> |
55 | 57 |
<hook hook="integrate_modify_modifications" function="SFSA::hook_modify_modifications" /> |
56 | 58 |
<hook hook="integrate_manage_logs" function="SFSA::hook_manage_logs" /> |
... | ... |
@@ -65,13 +67,13 @@ |
65 | 67 |
|
66 | 68 |
<!-- All the hooks, removed --> |
67 | 69 |
<!-- Main Section --> |
68 |
- <hook hook="integrate_pre_include" function="$sourcedir/StopForumSpam.php" reverse="true" /> |
|
70 |
+ <hook hook="integrate_pre_include" function="$sourcedir/SFS.php" reverse="true" /> |
|
69 | 71 |
<hook hook="integrate_pre_load" function="SFS::hook_pre_load" reverse="true" /> |
70 | 72 |
<hook hook="integrate_register" function="SFS::hook_register" reverse="true" /> |
71 | 73 |
<hook hook="integrate_create_control_verification_test" function="SFSA::hook_create_control_verification_test" reverse="true" /> |
72 | 74 |
|
73 | 75 |
<!-- Admin Section --> |
74 |
- <hook hook="integrate_admin_include" function="$sourcedir/StopForumSpamAdmin.php" reverse="true" /> |
|
76 |
+ <hook hook="integrate_admin_include" function="$sourcedir/SFS-Subs-Admin.php" reverse="true" /> |
|
75 | 77 |
<hook hook="integrate_admin_areas" function="SFSA::hook_admin_areas" reverse="true" /> |
76 | 78 |
<hook hook="integrate_modify_modifications" function="SFSA::hook_modify_modifications" reverse="true" /> |
77 | 79 |
<hook hook="integrate_manage_logs" function="SFSA::hook_manage_logs" reverse="true" /> |
... | ... |
@@ -80,7 +82,9 @@ |
80 | 82 |
<remove-file name="$themes_dir/default/languages/StopForumSpam.english.php" /> |
81 | 83 |
|
82 | 84 |
<!-- source files, removed --> |
83 |
- <remove-file name="$sourcedir/StopForumSpam.php" /> |
|
85 |
+ <remove-file name="$sourcedir/SFS.php" /> |
|
86 |
+ <remove-file name="$sourcedir/SFS-Subs-Admin.php" /> |
|
87 |
+ <remove-file name="$sourcedir/SFS-Subs-Logs.php" /> |
|
84 | 88 |
</uninstall> |
85 | 89 |
|
86 | 90 |
</package-info> |
87 | 91 |
\ No newline at end of file |
... | ... |
@@ -20,12 +20,12 @@ if (SMF == 'SSI') |
20 | 20 |
|
21 | 21 |
$hooks = array( |
22 | 22 |
// Main sections. |
23 |
- 'integrate_pre_include' => '$sourcedir/StopForumSpam.php', |
|
23 |
+ 'integrate_pre_include' => '$sourcedir/SFS.php', |
|
24 | 24 |
'integrate_pre_load' => 'SFS::hook_pre_load', |
25 | 25 |
'integrate_register' => 'SFS::hook_register', |
26 | 26 |
|
27 | 27 |
// Admin Sections. |
28 |
- 'integrate_admin_include' => '$sourcedir/StopForumSpamAdmin.php', |
|
28 |
+ 'integrate_admin_include' => '$sourcedir/SFS-Subs-Admin.php', |
|
29 | 29 |
'integrate_admin_areas' => 'SFSA::hook_admin_areas', |
30 | 30 |
'integrate_modify_modifications' => 'SFSA::hook_modify_modifications', |
31 | 31 |
'integrate_manage_logs' => 'SFSA::hook_manage_logs' |
... | ... |
@@ -20,12 +20,12 @@ if (SMF == 'SSI') |
20 | 20 |
|
21 | 21 |
$hooks = array( |
22 | 22 |
// Main sections. |
23 |
- 'integrate_pre_include' => '$sourcedir/StopForumSpam.php', |
|
23 |
+ 'integrate_pre_include' => '$sourcedir/SFS.php', |
|
24 | 24 |
'integrate_pre_load' => 'SFS::hook_pre_load', |
25 | 25 |
'integrate_register' => 'SFS::hook_register', |
26 | 26 |
|
27 | 27 |
// Admin Sections. |
28 |
- 'integrate_admin_include' => '$sourcedir/StopForumSpamAdmin.php', |
|
28 |
+ 'integrate_admin_include' => '$sourcedir/SFS-Subs-Admin.php', |
|
29 | 29 |
'integrate_admin_areas' => 'SFSA::hook_admin_areas', |
30 | 30 |
'integrate_modify_modifications' => 'SFSA::hook_modify_modifications', |
31 | 31 |
'integrate_manage_logs' => 'SFSA::hook_manage_logs' |
32 | 32 |