jdarwood007 commited on 2019-12-01 20:26:18
Showing 9 changed files, with 1599 additions and 0 deletions.
... | ... |
@@ -0,0 +1,29 @@ |
1 |
+BSD 3-Clause License |
|
2 |
+ |
|
3 |
+Copyright (c) 2019, SleePy |
|
4 |
+All rights reserved. |
|
5 |
+ |
|
6 |
+Redistribution and use in source and binary forms, with or without |
|
7 |
+modification, are permitted provided that the following conditions are met: |
|
8 |
+ |
|
9 |
+1. Redistributions of source code must retain the above copyright notice, this |
|
10 |
+ list of conditions and the following disclaimer. |
|
11 |
+ |
|
12 |
+2. Redistributions in binary form must reproduce the above copyright notice, |
|
13 |
+ this list of conditions and the following disclaimer in the documentation |
|
14 |
+ and/or other materials provided with the distribution. |
|
15 |
+ |
|
16 |
+3. Neither the name of the copyright holder nor the names of its |
|
17 |
+ contributors may be used to endorse or promote products derived from |
|
18 |
+ this software without specific prior written permission. |
|
19 |
+ |
|
20 |
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
21 |
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
22 |
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
23 |
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
|
24 |
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
25 |
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|
26 |
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
27 |
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
28 |
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
29 |
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
... | ... |
@@ -0,0 +1,7 @@ |
1 |
+A customization for SMF 2.0 or 2.1. |
|
2 |
+ |
|
3 |
+This has some setting compatibility with the original Stop Forum Spam as I was using it when I developed this. |
|
4 |
+ |
|
5 |
+This version includes logging, bulk checks and the ability to check non standard SMF verification fields. |
|
6 |
+ |
|
7 |
+This is in development as I develop its needs for SimpleDesk where I am primary using it. |
|
0 | 8 |
\ No newline at end of file |
... | ... |
@@ -0,0 +1,1218 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+class SFS |
|
4 |
+{ |
|
5 |
+ /* Some URLs */ |
|
6 |
+ private $urlSFSipCheck = 'https://www.stopforumspam.com/ipcheck/%1$s'; |
|
7 |
+ private $urlSFSsearch = 'https://www.stopforumspam.com/search/%1$s'; |
|
8 |
+ |
|
9 |
+ /* Our Software/Version Info defaults */ |
|
10 |
+ private $softwareName = 'smf'; |
|
11 |
+ private $softwareVersion = '2.1'; |
|
12 |
+ |
|
13 |
+ /* The admin page url */ |
|
14 |
+ private $adminPageURL = null; |
|
15 |
+ |
|
16 |
+ /* Settings we defaulted*/ |
|
17 |
+ private $changedSettings = array(); |
|
18 |
+ private $extraVerificationOptions = array(); |
|
19 |
+ |
|
20 |
+ /* Search stuff */ |
|
21 |
+ private $search_params = array(); |
|
22 |
+ private $search_params_column = ''; |
|
23 |
+ |
|
24 |
+ /* Logs Disabled for */ |
|
25 |
+ private $hoursDisabled = 24; |
|
26 |
+ |
|
27 |
+ /* Startup the class so we can call it later |
|
28 |
+ @hook: SMF2.0: integrate_admin_areas |
|
29 |
+ @hook: SMF2.1: integrate_admin_areas |
|
30 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
31 |
+ */ |
|
32 |
+ public static function hook_pre_load() |
|
33 |
+ { |
|
34 |
+ global $smcFunc; |
|
35 |
+ |
|
36 |
+ $smcFunc['classSFS'] = new SFS(); |
|
37 |
+ } |
|
38 |
+ |
|
39 |
+ /* |
|
40 |
+ We do this once we construct |
|
41 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
42 |
+ */ |
|
43 |
+ public function __construct() |
|
44 |
+ { |
|
45 |
+ global $smcFunc; |
|
46 |
+ |
|
47 |
+ // Is this SMF 2.0? |
|
48 |
+ if (!function_exists('loadCacheAccelerator')) |
|
49 |
+ $this->softwareVersion = '2.0'; |
|
50 |
+ |
|
51 |
+ // Setup the defaults. |
|
52 |
+ $this->loadDefaults(); |
|
53 |
+ } |
|
54 |
+ |
|
55 |
+ /* |
|
56 |
+ Admin Panel areas addition |
|
57 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
58 |
+ @hook: SMF2.0: integrate__admin_areas |
|
59 |
+ @hook: SMF2.1: integrate__admin_areas |
|
60 |
+ */ |
|
61 |
+ public static function hook_admin_areas(&$admin_areas) |
|
62 |
+ { |
|
63 |
+ global $smcFunc; |
|
64 |
+ return $smcFunc['classSFS']->setupAdminAreas($admin_areas); |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ /* |
|
68 |
+ Does the actual setup of the admin areas |
|
69 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
70 |
+ */ |
|
71 |
+ public function setupAdminAreas(&$admin_areas) |
|
72 |
+ { |
|
73 |
+ global $txt, $scripturl; |
|
74 |
+ |
|
75 |
+ // Get our language in here. |
|
76 |
+ $this->loadLanguage(); |
|
77 |
+ |
|
78 |
+ // Add the menu item. |
|
79 |
+ if ($this->versionCheck('2.0', 'smf')) |
|
80 |
+ { |
|
81 |
+ $this->adminPageURL = $scripturl . '?action=admin;area=modsettings;sa=sfs'; |
|
82 |
+ $this->adminLogURL = $scripturl . '?action=admin;area=modsettings;sa=sfslog'; |
|
83 |
+ |
|
84 |
+ $admin_areas['config']['areas']['modsettings']['subsections']['sfs'] = array( |
|
85 |
+ $txt['sfs_admin_area'] |
|
86 |
+ ); |
|
87 |
+ $admin_areas['config']['areas']['modsettings']['subsections']['sfslog'] = array( |
|
88 |
+ $txt['sfs_admin_logs'] |
|
89 |
+ ); |
|
90 |
+ } |
|
91 |
+ else |
|
92 |
+ { |
|
93 |
+ $this->adminPageURL = $scripturl . '?action=admin;area=securitysettings;sa=sfs'; |
|
94 |
+ $this->adminLogURL = $scripturl . '?action=admin;area=logs;sa=sfslog'; |
|
95 |
+ |
|
96 |
+ $admin_areas['config']['areas']['securitysettings']['subsections']['sfs'] = array( |
|
97 |
+ $txt['sfs_admin_area'] |
|
98 |
+ ); |
|
99 |
+ $admin_areas['config']['areas']['securitysettings']['subsections']['sfslog'] = array( |
|
100 |
+ $txt['sfs_admin_logs'] |
|
101 |
+ ); |
|
102 |
+ } |
|
103 |
+ |
|
104 |
+ return; |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ /* |
|
108 |
+ Only do this for 2.0, but we put it in the mod section. |
|
109 |
+ @hook: SMF2.0: integrate_modify_modifications |
|
110 |
+ @hook: SMF2.1: |
|
111 |
+ @CalledIn: SMF 2.0 |
|
112 |
+ */ |
|
113 |
+ public static function hook_modify_modifications(&$subActions) |
|
114 |
+ { |
|
115 |
+ global $smcFunc; |
|
116 |
+ return $smcFunc['classSFS']->setupModifyModifications($subActions); |
|
117 |
+ } |
|
118 |
+ |
|
119 |
+ /* |
|
120 |
+ Setup the Configuration page. |
|
121 |
+ @CalledIn: SMF 2.0 |
|
122 |
+ */ |
|
123 |
+ public function setupModifyModifications(&$subActions) |
|
124 |
+ { |
|
125 |
+ $subActions['sfs'] = 'SFS::startupAdminConfiguration'; |
|
126 |
+ |
|
127 |
+ // Only in SMF 2.0 do we drop logs here. |
|
128 |
+ if ($this->versionCheck('2.0', 'smf')) |
|
129 |
+ $subActions['sfslog'] = 'SFS::startupLogs'; |
|
130 |
+ |
|
131 |
+ return; |
|
132 |
+ } |
|
133 |
+ |
|
134 |
+ /* |
|
135 |
+ Only need to do this for SMF 2.0, SMF 2.1 calls hook_manage_logs |
|
136 |
+ @hook: SMF2.0: integrate_modify_modifications |
|
137 |
+ @CalledIn: SMF 2.0 |
|
138 |
+ */ |
|
139 |
+ public static function startupAdminConfiguration($return_config = false) |
|
140 |
+ { |
|
141 |
+ global $smcFunc; |
|
142 |
+ return $smcFunc['classSFS']->setupSFSConfiguration($return_config); |
|
143 |
+ } |
|
144 |
+ |
|
145 |
+ /* |
|
146 |
+ The settings page. |
|
147 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
148 |
+ */ |
|
149 |
+ public function setupSFSConfiguration($return_config = false) |
|
150 |
+ { |
|
151 |
+ global $txt, $scripturl, $context, $settings, $sc, $modSettings; |
|
152 |
+ |
|
153 |
+ $config_vars = array( |
|
154 |
+ array('title', 'sfsgentitle', 'label' => $txt['sfs_general_title']), |
|
155 |
+ |
|
156 |
+ array('check', 'sfs_enabled'), |
|
157 |
+ array('check', 'sfs_log_debug'), |
|
158 |
+ '', |
|
159 |
+ array('check', 'sfs_emailcheck'), |
|
160 |
+ array('check', 'sfs_ipcheck'), |
|
161 |
+ array('check', 'sfs_usernamecheck'), |
|
162 |
+ '', |
|
163 |
+ array('select', 'sfs_region', $this->sfsServerMapping('config')), |
|
164 |
+ '', |
|
165 |
+ array('check', 'sfs_wildcard_email'), |
|
166 |
+ array('check', 'sfs_wildcard_username'), |
|
167 |
+ array('check', 'sfs_wildcard_ip'), |
|
168 |
+ '', |
|
169 |
+ array('select', 'sfs_tor_check', array( |
|
170 |
+ 0 => $txt['sfs_tor_check_block'], |
|
171 |
+ 1 => $txt['sfs_tor_check_ignore'], |
|
172 |
+ 2 => $txt['sfs_tor_check_bad'], |
|
173 |
+ )), |
|
174 |
+ |
|
175 |
+ '', |
|
176 |
+ array('title', 'sfsverftitle', 'label' => $txt['sfs_verification_title']), |
|
177 |
+ array('desc', 'sfsverfdesc', 'label' => $txt['sfs_verification_desc']), |
|
178 |
+ array('select', 'sfs_verification_options', array( |
|
179 |
+ 'post' => $txt['sfs_verification_options_post'], |
|
180 |
+ 'report' => $txt['sfs_verification_options_report'], |
|
181 |
+ 'search' => $txt['sfs_verification_options_search'], |
|
182 |
+ ), 'multiple' => true), |
|
183 |
+ array('text', 'sfs_verification_options_extra', 'subtext' => $txt['sfs_verification_options_extra_subtext']), |
|
184 |
+ |
|
185 |
+ '', |
|
186 |
+ array('select', 'sfs_verification_options_members', array( |
|
187 |
+ 'post' => $txt['sfs_verification_options_post'], |
|
188 |
+ 'search' => $txt['sfs_verification_options_search'], |
|
189 |
+ ), 'multiple' => true), |
|
190 |
+ array('text', 'sfs_verification_options_membersextra', 'subtext' => $txt['sfs_verification_options_extra_subtext']), |
|
191 |
+ array('int', 'sfs_verification_options_members_post_threshold'), |
|
192 |
+ ); |
|
193 |
+ |
|
194 |
+ if ($return_config) |
|
195 |
+ return $config_vars; |
|
196 |
+ |
|
197 |
+ // Saving? |
|
198 |
+ if (isset($_GET['save'])) |
|
199 |
+ { |
|
200 |
+ // Turn the defaults off. |
|
201 |
+ $this->unloadDefaults(); |
|
202 |
+ checkSession(); |
|
203 |
+ |
|
204 |
+ saveDBSettings($config_vars); |
|
205 |
+ |
|
206 |
+ writeLog(); |
|
207 |
+ redirectexit($this->adminPageURL); |
|
208 |
+ } |
|
209 |
+ |
|
210 |
+ $context['post_url'] = $this->adminPageURL . ';save'; |
|
211 |
+ |
|
212 |
+ prepareDBSettingContext($config_vars); |
|
213 |
+ |
|
214 |
+ return; |
|
215 |
+ } |
|
216 |
+ |
|
217 |
+ /* |
|
218 |
+ In SMF 2.1 we do this hook. |
|
219 |
+ @hook: SMF2.0: |
|
220 |
+ @hook: SMF2.1: integrate_manage_logs |
|
221 |
+ @CalledIn: SMF 2.1 |
|
222 |
+ */ |
|
223 |
+ public static function hook_manage_logs(&$log_functions) |
|
224 |
+ { |
|
225 |
+ global $smcFunc; |
|
226 |
+ |
|
227 |
+ $log_functions['sfslog'] = array('StopForumSpam.php', 'startupLogs'); |
|
228 |
+ |
|
229 |
+ $context[$context['admin_menu_name']]['tab_data']['tabs']['sfslog'] = array( |
|
230 |
+ 'description' => $txt['sfs_admin_logs'], |
|
231 |
+ ); |
|
232 |
+ |
|
233 |
+ return; |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ /* |
|
237 |
+ Show the logs as called by SMF from either hook_manage_logs (SMF 2.1) or setupModifyModifications (SMF 2.0) |
|
238 |
+ */ |
|
239 |
+ public static function startupLogs($return_config = false) |
|
240 |
+ { |
|
241 |
+ global $smcFunc; |
|
242 |
+ |
|
243 |
+ // No Configs. |
|
244 |
+ if ($return_config) |
|
245 |
+ return array(); |
|
246 |
+ |
|
247 |
+ return $smcFunc['classSFS']->loadLogs(); |
|
248 |
+ } |
|
249 |
+ |
|
250 |
+ /* |
|
251 |
+ Actually load up logs |
|
252 |
+ */ |
|
253 |
+ public function loadLogs($return_config = false) |
|
254 |
+ { |
|
255 |
+ global $context, $txt, $smcFunc, $sourcedir; |
|
256 |
+ |
|
257 |
+ // No Configs. |
|
258 |
+ if ($return_config) |
|
259 |
+ return array(); |
|
260 |
+ |
|
261 |
+ loadLanguage('Modlog'); |
|
262 |
+ |
|
263 |
+ $context['url_start'] = $this->adminLogURL; |
|
264 |
+ $context['page_title'] = $txt['sfs_admin_logs']; |
|
265 |
+ $context['can_delete'] = allowedTo('admin_forum'); |
|
266 |
+ |
|
267 |
+ // Remove all.. |
|
268 |
+ if (isset($_POST['removeall']) && $context['can_delete']) |
|
269 |
+ $this->removeAllLogs(); |
|
270 |
+ elseif (!empty($_POST['remove']) && isset($_POST['delete']) && $context['can_delete']) |
|
271 |
+ $this->removeLogs(array_unique($_POST['delete'])); |
|
272 |
+ |
|
273 |
+ $sort_types = array( |
|
274 |
+ 'id_type' =>'l.id_type', |
|
275 |
+ 'log_time' => 'l.log_time', |
|
276 |
+ 'member' => 'mem.id_member', |
|
277 |
+ 'username' => 'l.username', |
|
278 |
+ 'email' => 'l.email', |
|
279 |
+ 'ip' => 'l.ip', |
|
280 |
+ 'ip2' => 'l.ip2', |
|
281 |
+ ); |
|
282 |
+ |
|
283 |
+ $context['order'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $_REQUEST['sort'] : 'time'; |
|
284 |
+ |
|
285 |
+ // Handle searches. |
|
286 |
+ $this->handleLogSearch(); |
|
287 |
+ |
|
288 |
+ require_once($sourcedir . '/Subs-List.php'); |
|
289 |
+ |
|
290 |
+ $listOptions = array( |
|
291 |
+ 'id' => 'sfslog_list', |
|
292 |
+ 'title' => $txt['sfs_admin_logs'], |
|
293 |
+ 'width' => '100%', |
|
294 |
+ 'items_per_page' => '50', |
|
295 |
+ 'no_items_label' => $txt['sfs_log_no_entries_found'], |
|
296 |
+ 'base_href' => $context['url_start'] . (!empty($context['search_params']) ? ';params=' . $context['search_params'] : ''), |
|
297 |
+ 'default_sort_col' => 'time', |
|
298 |
+ 'get_items' => array( |
|
299 |
+ 'function' => array($this, 'getSFSLogEntries'), |
|
300 |
+ 'params' => array( |
|
301 |
+ (!empty($this->search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''), |
|
302 |
+ array('sql_type' => $this->search_params_column, 'search_string' => $this->search_params['string']), |
|
303 |
+ ), |
|
304 |
+ ), |
|
305 |
+ 'get_count' => array( |
|
306 |
+ 'function' => array($this, 'getSFSLogEntriesCount'), |
|
307 |
+ 'params' => array( |
|
308 |
+ (!empty($this->search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : ''), |
|
309 |
+ array('sql_type' => $this->search_params_column, 'search_string' => $this->search_params['string']), |
|
310 |
+ ), |
|
311 |
+ ), |
|
312 |
+ // This assumes we are viewing by user. |
|
313 |
+ 'columns' => array( |
|
314 |
+ 'type' => array( |
|
315 |
+ 'header' => array( |
|
316 |
+ 'value' => $txt['sfs_log_header_type'], |
|
317 |
+ 'class' => 'lefttext', |
|
318 |
+ ), |
|
319 |
+ 'data' => array( |
|
320 |
+ 'db' => 'type', |
|
321 |
+ 'class' => 'smalltext', |
|
322 |
+ ), |
|
323 |
+ 'sort' => array( |
|
324 |
+ ), |
|
325 |
+ ), |
|
326 |
+ 'time' => array( |
|
327 |
+ 'header' => array( |
|
328 |
+ 'value' => $txt['sfs_log_header_time'], |
|
329 |
+ 'class' => 'lefttext', |
|
330 |
+ ), |
|
331 |
+ 'data' => array( |
|
332 |
+ 'db' => 'time', |
|
333 |
+ 'class' => 'smalltext', |
|
334 |
+ ), |
|
335 |
+ 'sort' => array( |
|
336 |
+ 'default' => 'l.log_time DESC', |
|
337 |
+ 'reverse' => 'l.log_time', |
|
338 |
+ ), |
|
339 |
+ ), |
|
340 |
+ 'member' => array( |
|
341 |
+ 'header' => array( |
|
342 |
+ 'value' => $txt['sfs_log_header_member'], |
|
343 |
+ 'class' => 'lefttext', |
|
344 |
+ ), |
|
345 |
+ 'data' => array( |
|
346 |
+ 'db' => 'member_link', |
|
347 |
+ 'class' => 'smalltext', |
|
348 |
+ ), |
|
349 |
+ 'sort' => array( |
|
350 |
+ 'default' => 'mem.id_member', |
|
351 |
+ 'reverse' => 'mem.id_member DESC', |
|
352 |
+ ), |
|
353 |
+ ), |
|
354 |
+ 'username' => array( |
|
355 |
+ 'header' => array( |
|
356 |
+ 'value' => $txt['sfs_log_header_username'], |
|
357 |
+ 'class' => 'lefttext', |
|
358 |
+ ), |
|
359 |
+ 'data' => array( |
|
360 |
+ 'db' => 'username', |
|
361 |
+ 'class' => 'smalltext', |
|
362 |
+ ), |
|
363 |
+ 'sort' => array( |
|
364 |
+ 'default' => 'l.username', |
|
365 |
+ 'reverse' => 'l.username DESC', |
|
366 |
+ ), |
|
367 |
+ ), |
|
368 |
+ 'email' => array( |
|
369 |
+ 'header' => array( |
|
370 |
+ 'value' => $txt['sfs_log_header_email'], |
|
371 |
+ 'class' => 'lefttext', |
|
372 |
+ ), |
|
373 |
+ 'data' => array( |
|
374 |
+ 'db' => 'email', |
|
375 |
+ 'class' => 'smalltext', |
|
376 |
+ ), |
|
377 |
+ 'sort' => array( |
|
378 |
+ 'default' => 'l.email', |
|
379 |
+ 'reverse' => 'l.email DESC', |
|
380 |
+ ), |
|
381 |
+ ), |
|
382 |
+ 'ip' => array( |
|
383 |
+ 'header' => array( |
|
384 |
+ 'value' => $txt['sfs_log_header_ip'], |
|
385 |
+ 'class' => 'lefttext', |
|
386 |
+ ), |
|
387 |
+ 'data' => array( |
|
388 |
+ 'db' => 'ip', |
|
389 |
+ 'class' => 'smalltext', |
|
390 |
+ ), |
|
391 |
+ 'sort' => array( |
|
392 |
+ 'default' => 'l.ip', |
|
393 |
+ 'reverse' => 'l.ip DESC', |
|
394 |
+ ), |
|
395 |
+ ), |
|
396 |
+ 'ip2' => array( |
|
397 |
+ 'header' => array( |
|
398 |
+ 'value' => $txt['sfs_log_header_ip2'], |
|
399 |
+ 'class' => 'lefttext', |
|
400 |
+ ), |
|
401 |
+ 'data' => array( |
|
402 |
+ 'db' => 'ip2', |
|
403 |
+ 'class' => 'smalltext', |
|
404 |
+ ), |
|
405 |
+ 'sort' => array( |
|
406 |
+ 'default' => 'l.ip2', |
|
407 |
+ 'reverse' => 'l.ip2 DESC', |
|
408 |
+ ), |
|
409 |
+ ), |
|
410 |
+ 'checks' => array( |
|
411 |
+ 'header' => array( |
|
412 |
+ 'value' => $txt['sfs_log_checks'], |
|
413 |
+ 'class' => 'lefttext', |
|
414 |
+ ), |
|
415 |
+ 'data' => array( |
|
416 |
+ 'db' => 'checks', |
|
417 |
+ 'class' => 'smalltext', |
|
418 |
+ ), |
|
419 |
+ 'sort' => array(), |
|
420 |
+ ), |
|
421 |
+ 'result' => array( |
|
422 |
+ 'header' => array( |
|
423 |
+ 'value' => $txt['sfs_log_result'], |
|
424 |
+ 'class' => 'lefttext', |
|
425 |
+ ), |
|
426 |
+ 'data' => array( |
|
427 |
+ 'db' => 'result', |
|
428 |
+ 'class' => 'smalltext', |
|
429 |
+ ), |
|
430 |
+ 'sort' => array(), |
|
431 |
+ ), |
|
432 |
+ 'delete' => array( |
|
433 |
+ 'header' => array( |
|
434 |
+ 'value' => '<input type="checkbox" name="all" class="input_check" onclick="invertAll(this, this.form);" />', |
|
435 |
+ ), |
|
436 |
+ 'data' => array( |
|
437 |
+ 'function' => create_function('$entry', ' |
|
438 |
+ return \'<input type="checkbox" class="input_check" name="delete[]" value="\' . $entry[\'id\'] . \'"\' . ($entry[\'editable\'] ? \'\' : \' disabled="disabled"\') . \' />\'; |
|
439 |
+ '), |
|
440 |
+ 'style' => 'text-align: center;', |
|
441 |
+ ), |
|
442 |
+ ), |
|
443 |
+ ), |
|
444 |
+ 'form' => array( |
|
445 |
+ 'href' => $context['url_start'], |
|
446 |
+ 'include_sort' => true, |
|
447 |
+ 'include_start' => true, |
|
448 |
+ 'hidden_fields' => array( |
|
449 |
+ $context['session_var'] => $context['session_id'], |
|
450 |
+ 'params' => $context['search_params'] |
|
451 |
+ ), |
|
452 |
+ ), |
|
453 |
+ 'additional_rows' => array( |
|
454 |
+ array( |
|
455 |
+ 'position' => 'below_table_data', |
|
456 |
+ 'value' => ' |
|
457 |
+ ' . $txt['sfs_log_search'] . ' (' . $context['search']['label'] . '): |
|
458 |
+ <input type="text" name="search" size="18" value="' . $smcFunc['htmlspecialchars']($context['search']['string']) . '" class="input_text" /> <input type="submit" name="is_search" value="' . $txt['modlog_go'] . '" class="button_submit" /> |
|
459 |
+ ' . ($context['can_delete'] ? ' | |
|
460 |
+ <input type="submit" name="remove" value="' . $txt['modlog_remove'] . '" class="button_submit" /> |
|
461 |
+ <input type="submit" name="removeall" value="' . $txt['modlog_removeall'] . '" class="button_submit" />' : ''), |
|
462 |
+ ), |
|
463 |
+ ), |
|
464 |
+ ); |
|
465 |
+ |
|
466 |
+ // Create the watched user list. |
|
467 |
+ createList($listOptions); |
|
468 |
+ |
|
469 |
+ $context['sub_template'] = 'show_list'; |
|
470 |
+ $context['default_list'] = 'sfslog_list'; |
|
471 |
+ } |
|
472 |
+ |
|
473 |
+ /* |
|
474 |
+ Get the Log entries |
|
475 |
+ */ |
|
476 |
+ public function getSFSLogEntries($start, $items_per_page, $sort, $query_string = '', $query_params = array()) |
|
477 |
+ { |
|
478 |
+ global $context, $smcFunc, $txt; |
|
479 |
+ |
|
480 |
+ $result = $smcFunc['db_query']('', ' |
|
481 |
+ SELECT |
|
482 |
+ l.id_sfs, |
|
483 |
+ l.id_type, |
|
484 |
+ l.log_time, |
|
485 |
+ l.id_member, |
|
486 |
+ l.username, |
|
487 |
+ l.email, |
|
488 |
+ l.ip, |
|
489 |
+ l.ip2, |
|
490 |
+ l.checks, |
|
491 |
+ l.result, |
|
492 |
+ mem.real_name, |
|
493 |
+ mg.group_name |
|
494 |
+ FROM {db_prefix}log_sfs AS l |
|
495 |
+ LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = l.id_member) |
|
496 |
+ 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) |
|
497 |
+ WHERE id_type IS NOT NULL' |
|
498 |
+ . (!empty($query_string) ? ' |
|
499 |
+ AND ' . $query_string : '') . ' |
|
500 |
+ ORDER BY ' . $sort . ' |
|
501 |
+ LIMIT ' . $start . ', ' . $items_per_page, |
|
502 |
+ array_merge($query_params, array( |
|
503 |
+ 'reg_group_id' => 0, |
|
504 |
+ )) |
|
505 |
+ ); |
|
506 |
+ |
|
507 |
+ while ($row = $smcFunc['db_fetch_assoc']($result)) |
|
508 |
+ { |
|
509 |
+ $entries[$row['id_sfs']] = array( |
|
510 |
+ 'id' => $row['id_sfs'], |
|
511 |
+ 'type' => $txt['sfs_log_types_' . $row['id_type']], |
|
512 |
+ 'time' => timeformat($row['log_time']), |
|
513 |
+ 'timestamp' => forum_time(true, $row['log_time']), |
|
514 |
+ 'member_link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' : (empty($row['real_name']) ? ($txt['guest'] . (!empty($row['extra']['member_acted']) ? ' (' . $row['extra']['member_acted'] . ')' : '')) : $row['real_name']), |
|
515 |
+ 'username' => $row['username'], |
|
516 |
+ 'email' => $row['email'], |
|
517 |
+ 'ip' => '<a href="' . sprintf($this->urlSFSipCheck, $row['ip']) . '">' . $row['ip'] . '</a>', |
|
518 |
+ 'ip2' => '<a href="' . sprintf($this->urlSFSipCheck, $row['ip2']) . '">' . $row['ip2'] . '</a>', |
|
519 |
+ 'editable' => true, //time() > $row['log_time'] + $this->hoursDisabled * 3600, |
|
520 |
+ 'checks_raw' => $row['checks'], |
|
521 |
+ 'result_raw' => $row['result'], |
|
522 |
+ ); |
|
523 |
+ |
|
524 |
+ $checksDecoded = $this->decodeJSON($row['checks']); |
|
525 |
+ |
|
526 |
+ // Checks, username |
|
527 |
+ if ($row['id_type'] == 1) |
|
528 |
+ $entries[$row['id_sfs']]['checks'] = '<a href="' . sprintf($this->urlSFSsearch, $checksDecoded['value']) . '">' . $checksDecoded['value'] . '</a>'; |
|
529 |
+ elseif ($row['id_type'] == 2) |
|
530 |
+ $entries[$row['id_sfs']]['checks'] = '<a href="' . sprintf($this->urlSFSsearch, $checksDecoded['value']) . '">' . $checksDecoded['value'] . '</a>'; |
|
531 |
+ elseif ($row['id_type'] == 3) |
|
532 |
+ $entries[$row['id_sfs']]['checks'] = '<a href="' . sprintf($this->urlSFSsearch, $checksDecoded['value']) . '">' . $checksDecoded['value'] . '</a>'; |
|
533 |
+ else |
|
534 |
+ { |
|
535 |
+ $entries[$row['id_sfs']]['checks'] = ''; |
|
536 |
+ |
|
537 |
+ foreach ($checksDecoded as $key => $vkey) |
|
538 |
+ foreach ($vkey as $key => $value) |
|
539 |
+ $entries[$row['id_sfs']]['checks'] .= ucfirst($key) . ':' . $value . '<br>'; |
|
540 |
+ } |
|
541 |
+ |
|
542 |
+ // $results |
|
543 |
+ if (strpos($row['result'], ',') !== false) |
|
544 |
+ { |
|
545 |
+ list($resultType, $resultMatch) = explode(',', $row['result']); |
|
546 |
+ $entries[$row['id_sfs']]['result'] = 'Matched on ' . $resultType . ' [' . $resultMatch . ']'; |
|
547 |
+ } |
|
548 |
+ else |
|
549 |
+ $entries[$row['id_sfs']]['result'] = $row['result']; |
|
550 |
+ |
|
551 |
+ } |
|
552 |
+ $smcFunc['db_free_result']($result); |
|
553 |
+ |
|
554 |
+ return $entries; |
|
555 |
+ } |
|
556 |
+ |
|
557 |
+ /* |
|
558 |
+ Get the Counter Log entries |
|
559 |
+ */ |
|
560 |
+ public function getSFSLogEntriesCount($query_string = '', $query_params = array(), $log_type = 1) |
|
561 |
+ { |
|
562 |
+ global $smcFunc, $user_info; |
|
563 |
+ |
|
564 |
+ $result = $smcFunc['db_query']('', ' |
|
565 |
+ SELECT COUNT(*) |
|
566 |
+ FROM {db_prefix}log_sfs AS l |
|
567 |
+ LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = l.id_member) |
|
568 |
+ 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) |
|
569 |
+ WHERE id_type IS NOT NULL' |
|
570 |
+ . (!empty($query_string) ? ' |
|
571 |
+ AND ' . $query_string : ''), |
|
572 |
+ array_merge($query_params, array( |
|
573 |
+ 'reg_group_id' => 0, |
|
574 |
+ )) |
|
575 |
+ ); |
|
576 |
+ list ($entry_count) = $smcFunc['db_fetch_row']($result); |
|
577 |
+ $smcFunc['db_free_result']($result); |
|
578 |
+ |
|
579 |
+ return $entry_count; |
|
580 |
+ } |
|
581 |
+ |
|
582 |
+ /* |
|
583 |
+ Remove all logs, except for those 24 horus or newer. |
|
584 |
+ */ |
|
585 |
+ private function removeAllLogs() |
|
586 |
+ { |
|
587 |
+ global $smcFunc; |
|
588 |
+ |
|
589 |
+ checkSession(); |
|
590 |
+ |
|
591 |
+ $smcFunc['db_query']('', ' |
|
592 |
+ DELETE FROM {db_prefix}log_sfs |
|
593 |
+ WHERE log_time < {int:twenty_four_hours_wait}', |
|
594 |
+ array( |
|
595 |
+ 'twenty_four_hours_wait' => time() - $this->hoursDisabled * 3600, |
|
596 |
+ ) |
|
597 |
+ ); |
|
598 |
+ } |
|
599 |
+ |
|
600 |
+ /* |
|
601 |
+ Remove specific logs, except for those 24 horus or newer. |
|
602 |
+ */ |
|
603 |
+ private function removeLogs($entries) |
|
604 |
+ { |
|
605 |
+ global $smcFunc; |
|
606 |
+ |
|
607 |
+ checkSession(); |
|
608 |
+ |
|
609 |
+ $smcFunc['db_query']('', ' |
|
610 |
+ DELETE FROM {db_prefix}log_sfs |
|
611 |
+ WHERE id_sfs IN ({array_string:delete_actions}) |
|
612 |
+ AND log_time < {int:twenty_four_hours_wait}', |
|
613 |
+ array( |
|
614 |
+ 'twenty_four_hours_wait' => time() - $this->hoursDisabled * 3600, |
|
615 |
+ 'delete_actions' => $entries, |
|
616 |
+ ) |
|
617 |
+ ); |
|
618 |
+ } |
|
619 |
+ |
|
620 |
+ /* |
|
621 |
+ Handle registration events |
|
622 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
623 |
+ @calledAt: action=signup, action=admin;area=regcenter;sa=register |
|
624 |
+ @hook: SMF2.0: integrate_register |
|
625 |
+ @hook: SMF2.1: integrate_register |
|
626 |
+ */ |
|
627 |
+ public static function hook_register(&$regOptions, &$theme_vars) |
|
628 |
+ { |
|
629 |
+ global $smcFunc; |
|
630 |
+ return $smcFunc['classSFS']->checkRegisterRequest($regOptions, $theme_vars); |
|
631 |
+ } |
|
632 |
+ |
|
633 |
+ /* |
|
634 |
+ Something is attempting to register, we should check them out. |
|
635 |
+ */ |
|
636 |
+ public function checkRegisterRequest(&$regOptions, &$theme_vars) |
|
637 |
+ { |
|
638 |
+ // Admins are not spammers.. usually. |
|
639 |
+ if ($regOptions['interface'] == 'admin') |
|
640 |
+ return true; |
|
641 |
+ // Get our language in here. |
|
642 |
+ $this->loadLanguage(); |
|
643 |
+ |
|
644 |
+ // Pass everything and let us handle what options we pass on. We pass the register_vars as these are what we have cleaned up. |
|
645 |
+ $this->sfsCheck(array( |
|
646 |
+ array('username' => $regOptions['register_vars']['member_name']), |
|
647 |
+ array('email' => $regOptions['register_vars']['email_address']), |
|
648 |
+ array('ip' => $regOptions['register_vars']['member_ip']), |
|
649 |
+ array('ip' => $regOptions['register_vars']['member_ip2']), |
|
650 |
+ ), 'register'); |
|
651 |
+ } |
|
652 |
+ |
|
653 |
+ /* |
|
654 |
+ Handle verification events, except register. |
|
655 |
+ @CalledIn: SMF 2.1 |
|
656 |
+ @hook: SMF2.1: integrate_create_control_verification_test |
|
657 |
+ */ |
|
658 |
+ public static function hook_create_control_verification_test($thisVerification, &$verification_errors) |
|
659 |
+ { |
|
660 |
+ global $smcFunc; |
|
661 |
+ $smcFunc['classSFS']->checkVerificationTest($thisVerification, $verification_errors); |
|
662 |
+ } |
|
663 |
+ |
|
664 |
+ /* |
|
665 |
+ Something is attempting to post, we should check them out. |
|
666 |
+ SMF 2.0 calls this directly as it doesnn't have a hook. |
|
667 |
+ */ |
|
668 |
+ public function checkVerificationTest($thisVerification, &$verification_errors) |
|
669 |
+ { |
|
670 |
+ global $user_info; |
|
671 |
+ |
|
672 |
+ // Registration is skipped as we process that differently. |
|
673 |
+ if ($thisVerification['id'] == 'register') |
|
674 |
+ return true; |
|
675 |
+ |
|
676 |
+ // Get our language in here. |
|
677 |
+ $this->loadLanguage(); |
|
678 |
+ |
|
679 |
+ $options = $this->getVerificationOptions(); |
|
680 |
+ |
|
681 |
+ // Posting? |
|
682 |
+ if ($thisVerification['id'] == 'post' && in_array('post', $options)) |
|
683 |
+ { |
|
684 |
+ // Guests! |
|
685 |
+ if ($user_info['is_guest']) |
|
686 |
+ { |
|
687 |
+ $guestname = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']); |
|
688 |
+ $email = !isset($_POST['email']) ? '' : trim($_POST['email']); |
|
689 |
+ |
|
690 |
+ return $this->sfsCheck(array( |
|
691 |
+ array('username' => $guestname), |
|
692 |
+ array('email' => $email), |
|
693 |
+ array('ip' => $user_info['ip']), |
|
694 |
+ array('ip' => $user_info['ip2']), |
|
695 |
+ ), 'post'); |
|
696 |
+ |
|
697 |
+ } |
|
698 |
+ // Members and they don't have enough posts? |
|
699 |
+ elseif (empty($user_info['posts']) || $user_info['posts'] < $modSettings['sfs_verification_options_members_post_threshold']) |
|
700 |
+ return $this->sfsCheck(array( |
|
701 |
+ array('username' => $user_info['username']), |
|
702 |
+ array('email' => $user_info['email']), |
|
703 |
+ array('ip' => $user_info['ip']), |
|
704 |
+ array('ip' => $user_info['ip2']), |
|
705 |
+ ), 'post'); |
|
706 |
+ else |
|
707 |
+ return true; |
|
708 |
+ } |
|
709 |
+ // reporting topics is only for guests. |
|
710 |
+ elseif ($thisVerification['id'] == 'report' && in_array('report', $options)) |
|
711 |
+ { |
|
712 |
+ $email = !isset($_POST['email']) ? '' : trim($_POST['email']); |
|
713 |
+ |
|
714 |
+ return $this->sfsCheck(array( |
|
715 |
+ array('email' => $email), |
|
716 |
+ array('ip' => $user_info['ip']), |
|
717 |
+ array('ip' => $user_info['ip2']), |
|
718 |
+ ), 'post'); |
|
719 |
+ } |
|
720 |
+ // We should avoid this on searches, as we can only send ips. |
|
721 |
+ elseif ($thisVerification['id'] == 'search' && in_array('search', $options) && ($user_info['is_guest'] || empty($user_info['posts']) || $user_info['posts'] < $modSettings['sfs_verification_options_members_post_threshold'])) |
|
722 |
+ { |
|
723 |
+ return $this->sfsCheck(array( |
|
724 |
+ array('ip' => $user_info['ip']), |
|
725 |
+ array('ip' => $user_info['ip2']), |
|
726 |
+ ), 'search'); |
|
727 |
+ } |
|
728 |
+ |
|
729 |
+ // Others areas. We have to play a guessing game here. |
|
730 |
+ foreach ($this->extraVerificationOptions as $option) |
|
731 |
+ { |
|
732 |
+ // Not a match. |
|
733 |
+ if ($thisVerification['id'] != $option) |
|
734 |
+ continue; |
|
735 |
+ |
|
736 |
+ // Always try to send off IPs. |
|
737 |
+ $checks = array( |
|
738 |
+ array('ip' => $user_info['ip']), |
|
739 |
+ array('ip' => $user_info['ip2']), |
|
740 |
+ ); |
|
741 |
+ |
|
742 |
+ // Can we find a username? |
|
743 |
+ $possibleUserNames = array('username', 'user_name', 'user', 'name', 'realname'); |
|
744 |
+ foreach ($possibleUserNames as $searchKey) |
|
745 |
+ if (!empty($_POST[$searchKey])) |
|
746 |
+ { |
|
747 |
+ $checks[] = array('username', $_POST[$searchKey]); |
|
748 |
+ break; |
|
749 |
+ } |
|
750 |
+ |
|
751 |
+ // Can we find a email? |
|
752 |
+ $possibleUserNames = array('email', 'emailaddress', 'email_address'); |
|
753 |
+ foreach ($possibleUserNames as $searchKey) |
|
754 |
+ if (!empty($_POST[$searchKey])) |
|
755 |
+ { |
|
756 |
+ $checks[] = array('email', $_POST[$searchKey]); |
|
757 |
+ break; |
|
758 |
+ } |
|
759 |
+ |
|
760 |
+ return $this->sfsCheck($checks, $option); |
|
761 |
+ } |
|
762 |
+die; |
|
763 |
+ } |
|
764 |
+ |
|
765 |
+ /* |
|
766 |
+ Check data against the SFS database |
|
767 |
+ */ |
|
768 |
+ public function sfsCheck($checks, $area = null) |
|
769 |
+ { |
|
770 |
+ global $sourcedir, $smcFunc, $context, $modSettings, $txt; |
|
771 |
+ |
|
772 |
+ $requestURL = $this->buildServerURL(); |
|
773 |
+ |
|
774 |
+ // Lets build our data set, always send it as a bulk. |
|
775 |
+ $singleCheckFound = false; |
|
776 |
+ foreach ($checks as $chk) |
|
777 |
+ { |
|
778 |
+ foreach ($chk as $type => $value) |
|
779 |
+ { |
|
780 |
+ // Hold up, we are not processing this check. |
|
781 |
+ if ( |
|
782 |
+ ($type == 'email' && empty($modSettings['sfs_emailcheck'])) || |
|
783 |
+ ($type == 'username' && empty($modSettings['sfs_usernamecheck'])) || |
|
784 |
+ ($type == 'ip' && empty($modSettings['sfs_ipcheck'])) |
|
785 |
+ ) |
|
786 |
+ continue; |
|
787 |
+ |
|
788 |
+ // No value? Can't do this. |
|
789 |
+ if (empty($value)) |
|
790 |
+ continue; |
|
791 |
+ |
|
792 |
+ // Emails and usernames must be UTF-8, Only a issue with SMF 2.0. |
|
793 |
+ if (!$context['utf8'] && ($type == 'email' || $type == 'username')) |
|
794 |
+ $requestURL .= '&' . $type . '[]=' . iconv($context['character_set'], 'UTF-8//IGNORE', $value); |
|
795 |
+ else |
|
796 |
+ $requestURL .= '&' . $type . '[]=' . urlencode($value); |
|
797 |
+ |
|
798 |
+ $singleCheckFound = true; |
|
799 |
+ } |
|
800 |
+ } |
|
801 |
+ |
|
802 |
+ // No checks found? Can't do this. |
|
803 |
+ if (empty($singleCheckFound)) |
|
804 |
+ { |
|
805 |
+ $this->logAllStats('error', $checks, 'error'); |
|
806 |
+ log_error($txt['sfs_request_failure_nodata'] . ':' . $requestURL, 'critical'); |
|
807 |
+ return true; |
|
808 |
+ } |
|
809 |
+ |
|
810 |
+ // SMF 2.0 has the fetch_web_data in the Subs-Packages, 2.1 it is in Subs.php. |
|
811 |
+ if ($this->versionCheck('2.0', 'smf')) |
|
812 |
+ require_once($sourcedir . '/Subs-Package.php'); |
|
813 |
+ |
|
814 |
+ // Now we have a URL, lets go get it. |
|
815 |
+ $response = $this->decodeJSON(fetch_web_data($requestURL)); |
|
816 |
+ |
|
817 |
+ // No data received, log it and let them through. |
|
818 |
+ if (empty($response)) |
|
819 |
+ { |
|
820 |
+ $this->logAllStats('error', $checks, 'failure'); |
|
821 |
+ log_error($txt['sfs_request_failure'] . ':' . $requestURL, 'critical'); |
|
822 |
+ return true; |
|
823 |
+ } |
|
824 |
+ |
|
825 |
+ $requestBlocked = false; |
|
826 |
+ |
|
827 |
+ // Handle IPs only if we are supposed to, this is just a double check. |
|
828 |
+ if (!empty($modSettings['sfs_ipcheck']) && !empty($response['ip'])) |
|
829 |
+ { |
|
830 |
+ foreach ($response['ip'] as $check) |
|
831 |
+ { |
|
832 |
+ // !!! TODO: Frequency 255 is a blacklist, maybe add them to a generic ban list? |
|
833 |
+ if (!empty($check['appears'])) |
|
834 |
+ { |
|
835 |
+ $this->logBlockedStats('ip', $check); |
|
836 |
+ $requestBlocked = 'ip,' . $smcFunc['htmlspecialchars']($check['value']); |
|
837 |
+ break; |
|
838 |
+ } |
|
839 |
+ } |
|
840 |
+ } |
|
841 |
+ |
|
842 |
+ // If we didn't match a IP, handle Usernames only if we are supposed to, this is just a double check. |
|
843 |
+ if (empty($requestBlocked) && !empty($modSettings['sfs_usernamecheck']) && !empty($response['username'])) |
|
844 |
+ { |
|
845 |
+ foreach ($response['username'] as $check) |
|
846 |
+ { |
|
847 |
+ // !!! TODO: Expose confidence as a threshold? |
|
848 |
+ // Combine with $area we could also require admin approval above thresholds on things like register. |
|
849 |
+ // !!! TODO: Expose lastseen as a threshold? |
|
850 |
+ if (!empty($check['appears'])) |
|
851 |
+ { |
|
852 |
+ $this->logBlockedStats('username', $check); |
|
853 |
+ $requestBlocked = 'username,' . $smcFunc['htmlspecialchars']($check['value']); |
|
854 |
+ break; |
|
855 |
+ } |
|
856 |
+ } |
|
857 |
+ } |
|
858 |
+ |
|
859 |
+ // If we didn't match a IP or username, handle Emails only if we are supposed to, this is just a double check. |
|
860 |
+ if (empty($requestBlocked) && !empty($modSettings['sfs_emailcheck']) && !empty($response['email'])) |
|
861 |
+ { |
|
862 |
+ foreach ($response['email'] as $check) |
|
863 |
+ { |
|
864 |
+ if (!empty($check['appears'])) |
|
865 |
+ { |
|
866 |
+ $this->logBlockedStats('email', $check); |
|
867 |
+ $requestBlocked = 'email,' . $smcFunc['htmlspecialchars']($check['value']); |
|
868 |
+ break; |
|
869 |
+ } |
|
870 |
+ } |
|
871 |
+ } |
|
872 |
+ |
|
873 |
+ |
|
874 |
+ // Log all the stats? Debug mode here. |
|
875 |
+ if (!empty($modSettings['sfs_log_debug'])) |
|
876 |
+ $this->logAllStats('all', $checks, $requestBlocked); |
|
877 |
+ |
|
878 |
+ // At this point, we have checked everything, do what needs to be done for our good person. |
|
879 |
+ if (!$requestBlocked) |
|
880 |
+ return true; |
|
881 |
+ |
|
882 |
+ // You are a bad spammer, don't tell them what was blocked. |
|
883 |
+ $this->loadLanguage(); |
|
884 |
+ fatal_error($txt['sfs_request_blocked']); |
|
885 |
+ } |
|
886 |
+ |
|
887 |
+ /* |
|
888 |
+ Log the blocked request for later |
|
889 |
+ */ |
|
890 |
+ private function logBlockedStats($type, $check) |
|
891 |
+ { |
|
892 |
+ global $smcFunc, $user_info; |
|
893 |
+ |
|
894 |
+ switch($type) |
|
895 |
+ { |
|
896 |
+ case 'username': |
|
897 |
+ $blockType = 1; |
|
898 |
+ break; |
|
899 |
+ case 'email': |
|
900 |
+ $blockType = 2; |
|
901 |
+ break; |
|
902 |
+ case 'ip': |
|
903 |
+ $blockType = 3; |
|
904 |
+ break; |
|
905 |
+ default: |
|
906 |
+ $blockType = 99; |
|
907 |
+ break; |
|
908 |
+ } |
|
909 |
+ |
|
910 |
+ $smcFunc['db_insert']('', |
|
911 |
+ '{db_prefix}log_sfs', |
|
912 |
+ array('id_type' => 'int', 'log_time' => 'int', 'id_member' => 'int', 'username' => 'string', 'email' => 'string', 'ip' => 'string', 'ip2' => 'string', 'checks' => 'string', 'result' => 'string'), |
|
913 |
+ array( |
|
914 |
+ $blockType, // Blocked request |
|
915 |
+ time(), |
|
916 |
+ $user_info['id'], |
|
917 |
+ $type == 'username' ? $check['value'] : '', |
|
918 |
+ $type == 'email' ? $check['value'] : '', |
|
919 |
+ $type == 'ip' ? $check['value'] : $user_info['ip'], |
|
920 |
+ $user_info['ip2'], |
|
921 |
+ json_encode($check), |
|
922 |
+ 'Blocked' |
|
923 |
+ ), |
|
924 |
+ array('id_sfs', 'id_type') |
|
925 |
+ ); |
|
926 |
+ } |
|
927 |
+ |
|
928 |
+ /* |
|
929 |
+ Log all the data for later. |
|
930 |
+ */ |
|
931 |
+ private function logAllStats($type, $checks, $requestBlocked) |
|
932 |
+ { |
|
933 |
+ global $smcFunc, $user_info; |
|
934 |
+ |
|
935 |
+ $smcFunc['db_insert']('', |
|
936 |
+ '{db_prefix}log_sfs', |
|
937 |
+ array('id_type' => 'int', 'log_time' => 'int', 'id_member' => 'int', 'username' => 'string', 'email' => 'string', 'ip' => 'string', 'ip2' => 'string', 'checks' => 'string', 'result' => 'string'), |
|
938 |
+ array( |
|
939 |
+ 0, // Debug type. |
|
940 |
+ time(), |
|
941 |
+ $user_info['id'], |
|
942 |
+ '', // Username |
|
943 |
|
|
944 |
+ $user_info['ip'], |
|
945 |
+ $user_info['ip2'], |
|
946 |
+ json_encode($checks), |
|
947 |
+ $requestBlocked, |
|
948 |
+ ), |
|
949 |
+ array('id_sfs', 'id_type') |
|
950 |
+ ); |
|
951 |
+ } |
|
952 |
+ |
|
953 |
+ /* |
|
954 |
+ Decode JSON data. |
|
955 |
+ If we have $smcFunc['json_decode'] we use it as it can handle errors. |
|
956 |
+ Otherwise we do some basic stuff. |
|
957 |
+ */ |
|
958 |
+ private function decodeJSON($requestData) |
|
959 |
+ { |
|
960 |
+ global $smcFunc; |
|
961 |
+ |
|
962 |
+ // Do we have $smcFunc? It handles errors and logs them as needed. |
|
963 |
+ if (isset($smcFunc['json_decode']) && is_callable($smcFunc['json_decode'])) |
|
964 |
+ return $smcFunc['json_decode']($request, true); |
|
965 |
+ // Back to the basics. |
|
966 |
+ else |
|
967 |
+ { |
|
968 |
+ $data = @json_decode($requestData, true); |
|
969 |
+ |
|
970 |
+ // We got a error, return nothing. |
|
971 |
+ // !!! TODO: Log this? |
|
972 |
+ if (json_last_error() !== JSON_ERROR_NONE) |
|
973 |
+ return array(); |
|
974 |
+ return $data; |
|
975 |
+ } |
|
976 |
+ } |
|
977 |
+ |
|
978 |
+ /* |
|
979 |
+ Build the base URL for the Stop Forum Spam website |
|
980 |
+ @resource: https://www.stopforumspam.com/usage |
|
981 |
+ */ |
|
982 |
+ public function buildServerURL() |
|
983 |
+ { |
|
984 |
+ global $modSettings; |
|
985 |
+ static $url = null; |
|
986 |
+ |
|
987 |
+ // If we build this once, don't do it again. |
|
988 |
+ if (!empty($url)) |
|
989 |
+ return $url; |
|
990 |
+ |
|
991 |
+ // Get our server info. |
|
992 |
+ $this_server = $this->sfsServerMapping(); |
|
993 |
+ $server = $this_server[$modSettings['sfs_region']]; |
|
994 |
+ |
|
995 |
+ // Build the base URL, we always use json responses. |
|
996 |
+ $url = 'https://' . $server['host'] . '/api?json'; |
|
997 |
+ |
|
998 |
+ // Ignore all wildcard checks? |
|
999 |
+ if (!empty($modSettings['sfs_wildcard_email']) && !empty($modSettings['sfs_wildcard_username']) && !empty($modSettings['sfs_wildcard_ip'])) |
|
1000 |
+ $url .= '&nobadall'; |
|
1001 |
+ // Maybe only certain wildcards are ignored? |
|
1002 |
+ else |
|
1003 |
+ { |
|
1004 |
+ // Ignoring Wildcard Emails? |
|
1005 |
+ if (!empty($modSettings['sfs_wildcard_email'])) |
|
1006 |
+ $url .= '&nobadusername'; |
|
1007 |
+ |
|
1008 |
+ // Ignoring Wildcard Usernames? |
|
1009 |
+ if (!empty($modSettings['sfs_wildcard_username'])) |
|
1010 |
+ $url .= '&nobademail'; |
|
1011 |
+ |
|
1012 |
+ // Ignoring Wildcard IPs? |
|
1013 |
+ if (!empty($modSettings['sfs_wildcard_ip'])) |
|
1014 |
+ $url .= '&nobadip'; |
|
1015 |
+ } |
|
1016 |
+ |
|
1017 |
+ // Tor handling, ignore them all. Not recommended... |
|
1018 |
+ if (!empty($modSettings['sfs_tor_check']) && $modSettings['sfs_tor_check'] == 1) |
|
1019 |
+ $url .= '¬orexit'; |
|
1020 |
+ // Only block bad exit nodes. |
|
1021 |
+ elseif (!empty($modSettings['sfs_tor_check']) && $modSettings['sfs_tor_check'] == 2) |
|
1022 |
+ $url .= '&badtorexit'; |
|
1023 |
+ // Default handling for Tor is to block all exit nodes, nothing needed here. |
|
1024 |
+ |
|
1025 |
+ return $url; |
|
1026 |
+ } |
|
1027 |
+ |
|
1028 |
+ /* |
|
1029 |
+ Setup our possible SFS hosts. |
|
1030 |
+ @resource: https://www.stopforumspam.com/usage |
|
1031 |
+ */ |
|
1032 |
+ public function sfsServerMapping($returnType = null) |
|
1033 |
+ { |
|
1034 |
+ global $txt; |
|
1035 |
+ |
|
1036 |
+ // Global list of servers. |
|
1037 |
+ $serverList = array( |
|
1038 |
+ 0 => array( |
|
1039 |
+ 'region' => 'global', |
|
1040 |
+ 'label' => $txt['sfs_region_global'], |
|
1041 |
+ 'host' => 'api.stopforumspam.org', |
|
1042 |
+ ), |
|
1043 |
+ 1 => array( |
|
1044 |
+ 'region' => 'us', |
|
1045 |
+ 'label' => $txt['sfs_region_us'], |
|
1046 |
+ 'host' => 'us.stopforumspam.org', |
|
1047 |
+ ), |
|
1048 |
+ 2 => array( |
|
1049 |
+ 'region' => 'eu', |
|
1050 |
+ 'label' => $txt['sfs_region_eu'], |
|
1051 |
+ 'host' => 'eruope.stopforumspam.org', |
|
1052 |
+ ), |
|
1053 |
+ ); |
|
1054 |
+ |
|
1055 |
+ // Configs only need the labels. |
|
1056 |
+ if ($returnType == 'config') |
|
1057 |
+ { |
|
1058 |
+ $temp = array(); |
|
1059 |
+ foreach ($serverList as $id_server => $server) |
|
1060 |
+ $temp[$id_server] = $server['label']; |
|
1061 |
+ return $temp; |
|
1062 |
+ } |
|
1063 |
+ |
|
1064 |
+ return $serverList; |
|
1065 |
+ } |
|
1066 |
+ |
|
1067 |
+ /* |
|
1068 |
+ Verification Options |
|
1069 |
+ */ |
|
1070 |
+ private function getVerificationOptions() |
|
1071 |
+ { |
|
1072 |
+ global $user_info, $modSettings; |
|
1073 |
+ |
|
1074 |
+ $optionsKey = $user_info['is_guest'] ? 'sfs_verification_options' : 'sfs_verification_options_members'; |
|
1075 |
+ $optionsKeyExtra = $user_info['is_guest'] ? 'sfs_verification_options_extra' : 'sfs_verification_options_membersextra'; |
|
1076 |
+ |
|
1077 |
+ // Standard options. |
|
1078 |
+ if ($this->versionCheck('2.0', 'smf') && !empty($modSettings[$optionsKey])) |
|
1079 |
+ $options = safe_unserialize($modSettings[$optionsKey]); |
|
1080 |
+ elseif (!empty($modSettings[$optionsKey])) |
|
1081 |
+ $options = $this->decodeJSON($modSettings[$optionsKey]); |
|
1082 |
+ else |
|
1083 |
+ $options = array(); |
|
1084 |
+ |
|
1085 |
+ // Extras. |
|
1086 |
+ if (!empty($modSettings[$optionsKeyExtra])) |
|
1087 |
+ { |
|
1088 |
+ $this->extraVerificationOptions = explode(',', $modSettings[$optionsKeyExtra]); |
|
1089 |
+ $options = array_merge($options, $this->extraVerificationOptions); |
|
1090 |
+ } |
|
1091 |
+ |
|
1092 |
+ return $options; |
|
1093 |
+ } |
|
1094 |
+ |
|
1095 |
+ /* |
|
1096 |
+ Defaults for SFS |
|
1097 |
+ We don't specify all of them here, just what we need to make development easier. |
|
1098 |
+ */ |
|
1099 |
+ public function loadDefaults($undo = false) |
|
1100 |
+ { |
|
1101 |
+ global $modSettings; |
|
1102 |
+ |
|
1103 |
+ // Specify the defaults, but only non empties. |
|
1104 |
+ $defaultSettings = array( |
|
1105 |
+ 'sfs_enabled' => 1, |
|
1106 |
+ 'sfs_emailcheck' => 1, |
|
1107 |
+ 'sfs_region' => 0, |
|
1108 |
+ 'sfs_verification_options_members_post_threshold' => 5, |
|
1109 |
+ ); |
|
1110 |
+ |
|
1111 |
+ // SMF 2.0 is serialized, SMF 2.1 is json. |
|
1112 |
+ if ($this->versionCheck('2.0', 'smf')) |
|
1113 |
+ $defaultSettings['sfs_verification_options'] = serialize(array('post')); |
|
1114 |
+ else |
|
1115 |
+ $defaultSettings['sfs_verification_options'] = json_encode(array('post')); |
|
1116 |
+ |
|
1117 |
+ // We undoing this? Maybe a save? |
|
1118 |
+ if ($undo) |
|
1119 |
+ { |
|
1120 |
+ foreach ($this->changedSettings as $key => $value) |
|
1121 |
+ unset($modSettings[$key], $this->changedSettings[$key]); |
|
1122 |
+ return true; |
|
1123 |
+ } |
|
1124 |
+ |
|
1125 |
+ // Enabled settings. |
|
1126 |
+ foreach ($defaultSettings as $key => $value) |
|
1127 |
+ if (!isset($modSettings[$key])) |
|
1128 |
+ { |
|
1129 |
+ $this->changedSettings[$key] = null; |
|
1130 |
+ $modSettings[$key] = $value; |
|
1131 |
+ } |
|
1132 |
+ } |
|
1133 |
+ |
|
1134 |
+ /* |
|
1135 |
+ Just a wrapper to tell defaults to undo. |
|
1136 |
+ */ |
|
1137 |
+ public function unloadDefaults() |
|
1138 |
+ { |
|
1139 |
+ return $this->loadDefaults(true); |
|
1140 |
+ } |
|
1141 |
+ |
|
1142 |
+ /* |
|
1143 |
+ Global function to check version and software matches. |
|
1144 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
1145 |
+ */ |
|
1146 |
+ public function versionCheck($version, $software = 'smf') |
|
1147 |
+ { |
|
1148 |
+ // We can't do this if the software doesn't match. |
|
1149 |
+ if ($software !== $this->softwareName) |
|
1150 |
+ return false; |
|
1151 |
+ |
|
1152 |
+ // Allow multiple versions to pass. |
|
1153 |
+ $version = (array) $version; |
|
1154 |
+ foreach ($version as $v) |
|
1155 |
+ if ($v == $this->softwareVersion) |
|
1156 |
+ return true; |
|
1157 |
+ |
|
1158 |
+ // No match? False. |
|
1159 |
+ return false; |
|
1160 |
+ } |
|
1161 |
+ |
|
1162 |
+ /* |
|
1163 |
+ Global loadLanguage function, should we want to split it out or need to load it differently |
|
1164 |
+ @CalledIn: SMF 2.0, SMF 2.1 |
|
1165 |
+ */ |
|
1166 |
+ public function loadLanguage() |
|
1167 |
+ { |
|
1168 |
+ // Load the langauge. |
|
1169 |
+ loadLanguage('StopForumSpam'); |
|
1170 |
+ } |
|
1171 |
+ |
|
1172 |
+ /* |
|
1173 |
+ Handle searching for logs |
|
1174 |
+ */ |
|
1175 |
+ private function handleLogSearch() |
|
1176 |
+ { |
|
1177 |
+ global $context, $txt; |
|
1178 |
+ |
|
1179 |
+ if (!empty($_REQUEST['params']) && empty($_REQUEST['is_search'])) |
|
1180 |
+ { |
|
1181 |
+ $this->search_params = base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))); |
|
1182 |
+ $this->search_params = $this->JSONDecode($this->search_params); |
|
1183 |
+ } |
|
1184 |
+ |
|
1185 |
+ $searchTypes = array( |
|
1186 |
+ 'member' => array('sql' => 'mem.real_name', 'label' => $txt['sfs_log_search_member']), |
|
1187 |
+ 'username' => array('sql' => 'l.username', 'label' => $txt['sfs_log_search_username']), |
|
1188 |
+ 'email' => array('sql' => 'l.email', 'label' => $txt['sfs_log_search_email']), |
|
1189 |
+ 'ip' => array('sql' => 'lm.ip', 'label' => $txt['sfs_log_search_ip']), |
|
1190 |
+ 'ip2' => array('sql' => 'lm.ip2', 'label' => $txt['sfs_log_search_ip2']) |
|
1191 |
+ ); |
|
1192 |
+ |
|
1193 |
+ if (!isset($this->search_params['string']) || (!empty($_REQUEST['search']) && $this->search_params['string'] != $_REQUEST['search'])) |
|
1194 |
+ $this->search_params_string = empty($_REQUEST['search']) ? '' : $_REQUEST['search']; |
|
1195 |
+ else |
|
1196 |
+ $this->search_params_string = $this->search_params['string']; |
|
1197 |
+ |
|
1198 |
+ if (isset($_REQUEST['search_type']) || empty($this->search_params['type']) || !isset($searchTypes[$this->search_params['type']])) |
|
1199 |
+ $this->search_params_type = isset($_REQUEST['search_type']) && isset($searchTypes[$_REQUEST['search_type']]) ? $_REQUEST['search_type'] : (isset($searchTypes[$context['order']]) ? $context['order'] : 'member'); |
|
1200 |
+ else |
|
1201 |
+ $this->search_params_type = $this->search_params['type']; |
|
1202 |
+ |
|
1203 |
+ $this->search_params_column = $searchTypes[$this->search_params_type]['sql']; |
|
1204 |
+ $this->search_params = array( |
|
1205 |
+ 'string' => $this->search_params_string, |
|
1206 |
+ 'type' => $this->search_params_type, |
|
1207 |
+ ); |
|
1208 |
+ |
|
1209 |
+ // Setup the search context. |
|
1210 |
+ $context['search_params'] = empty($this->search_params['string']) ? '' : base64_encode(json_encode($this->search_params)); |
|
1211 |
+ $context['search'] = array( |
|
1212 |
+ 'string' => $this->search_params['string'], |
|
1213 |
+ 'type' => $this->search_params['type'], |
|
1214 |
+ 'label' => $searchTypes[$this->search_params_type]['label'], |
|
1215 |
+ ); |
|
1216 |
+ |
|
1217 |
+ } |
|
1218 |
+} |
|
0 | 1219 |
\ No newline at end of file |
... | ... |
@@ -0,0 +1,115 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+// If we have found SSI.php and we are outside of SMF, then we are running standalone. |
|
4 |
+if (file_exists(dirname(__FILE__) . '/SSI.php') && !defined('SMF')) |
|
5 |
+ require_once(dirname(__FILE__) . '/SSI.php'); |
|
6 |
+elseif (file_exists(getcwd() . '/SSI.php') && !defined('SMF')) |
|
7 |
+ require_once(getcwd() . '/SSI.php'); |
|
8 |
+elseif (!defined('SMF')) // If we are outside SMF and can't find SSI.php, then throw an error |
|
9 |
+ die('<b>Error:</b> Cannot install - please verify you put this file in the same place as SMF\'s SSI.php.'); |
|
10 |
+ |
|
11 |
+if (SMF == 'SSI') |
|
12 |
+ db_extend('packages'); |
|
13 |
+ |
|
14 |
+$table = array( |
|
15 |
+ 'table_name' => '{db_prefix}log_sfs', |
|
16 |
+ 'columns' => array( |
|
17 |
+ db_field('id_sfs', 'int', 0, true, true), |
|
18 |
+ db_field('id_type', 'tinyint', 0), |
|
19 |
+ db_field('log_time', 'int'), |
|
20 |
+ db_field('id_member', 'mediumint'), |
|
21 |
+ db_field('username', 'varchar', 255), |
|
22 |
+ db_field('email', 'varchar', 255), |
|
23 |
+ db_field('ip', 'varchar', 255), |
|
24 |
+ db_field('ip2', 'varchar', 255), |
|
25 |
+ db_field('checks', 'mediumtext'), |
|
26 |
+ db_field('result', 'mediumtext'), |
|
27 |
+ ), |
|
28 |
+ 'indexes' => array( |
|
29 |
+ array( |
|
30 |
+ 'columns' => array('id_sfs'), |
|
31 |
+ 'type' => 'primary', |
|
32 |
+ ), |
|
33 |
+ array( |
|
34 |
+ 'columns' => array('id_type'), |
|
35 |
+ 'type' => 'index', |
|
36 |
+ ), |
|
37 |
+ ), |
|
38 |
+ 'if_exists' => 'ignore', |
|
39 |
+ 'error' => 'fatal', |
|
40 |
+ 'parameters' => array(), |
|
41 |
+); |
|
42 |
+ |
|
43 |
+$smcFunc['db_create_table']($table['table_name'], $table['columns'], $table['indexes'], $table['parameters'], $table['if_exists'], $table['error']); |
|
44 |
+ |
|
45 |
+/* |
|
46 |
+ * Calculates the proper settings to use in a column. |
|
47 |
+ * |
|
48 |
+ * @since 1.0 |
|
49 |
+*/ |
|
50 |
+function db_field($name, $type, $size = 0, $unsigned = true, $auto = false) |
|
51 |
+{ |
|
52 |
+ $fields = array( |
|
53 |
+ 'varchar' => array( |
|
54 |
+ 'auto' => false, |
|
55 |
+ 'type' => 'varchar', |
|
56 |
+ 'size' => $size == 0 ? 50 : $size, |
|
57 |
+ 'null' => false, |
|
58 |
+ ), |
|
59 |
+ 'text' => array( |
|
60 |
+ 'auto' => false, |
|
61 |
+ 'type' => 'text', |
|
62 |
+ 'null' => false, |
|
63 |
+ ), |
|
64 |
+ 'mediumtext' => array( |
|
65 |
+ 'auto' => false, |
|
66 |
+ 'type' => 'mediumtext', |
|
67 |
+ 'null' => false, |
|
68 |
+ ), |
|
69 |
+ 'tinyint' => array( |
|
70 |
+ 'auto' => $auto, |
|
71 |
+ 'type' => 'tinyint', |
|
72 |
+ 'default' => 0, |
|
73 |
+ 'size' => empty($unsigned) ? 4 : 3, |
|
74 |
+ 'unsigned' => $unsigned, |
|
75 |
+ 'null' => false, |
|
76 |
+ ), |
|
77 |
+ 'smallint' => array( |
|
78 |
+ 'auto' => $auto, |
|
79 |
+ 'type' => 'smallint', |
|
80 |
+ 'default' => 0, |
|
81 |
+ 'size' => empty($unsigned) ? 6 : 5, |
|
82 |
+ 'unsigned' => $unsigned, |
|
83 |
+ 'null' => false, |
|
84 |
+ ), |
|
85 |
+ 'mediumint' => array( |
|
86 |
+ 'auto' => $auto, |
|
87 |
+ 'type' => 'mediumint', |
|
88 |
+ 'default' => 0, |
|
89 |
+ 'size' => 8, |
|
90 |
+ 'unsigned' => $unsigned, |
|
91 |
+ 'null' => false, |
|
92 |
+ ), |
|
93 |
+ 'int' => array( |
|
94 |
+ 'auto' => $auto, |
|
95 |
+ 'type' => 'int', |
|
96 |
+ 'default' => 0, |
|
97 |
+ 'size' => empty($unsigned) ? 11 : 10, |
|
98 |
+ 'unsigned' => $unsigned, |
|
99 |
+ 'null' => false, |
|
100 |
+ ), |
|
101 |
+ 'bigint' => array( |
|
102 |
+ 'auto' => $auto, |
|
103 |
+ 'type' => 'bigint', |
|
104 |
+ 'default' => 0, |
|
105 |
+ 'size' => 21, |
|
106 |
+ 'unsigned' => $unsigned, |
|
107 |
+ 'null' => false, |
|
108 |
+ ), |
|
109 |
+ ); |
|
110 |
+ |
|
111 |
+ $field = $fields[$type]; |
|
112 |
+ $field['name'] = $name; |
|
113 |
+ |
|
114 |
+ return $field; |
|
115 |
+} |
|
0 | 116 |
\ No newline at end of file |
... | ... |
@@ -0,0 +1,29 @@ |
1 |
+<?xml version="1.0"?> |
|
2 |
+<!DOCTYPE modification SYSTEM "http://www.simplemachines.org/xml/modification"> |
|
3 |
+<modification xmlns="http://www.simplemachines.org/xml/modification" xmlns:smf="http://www.simplemachines.org/"> |
|
4 |
+ <id>SleePy:StopForumSpam</id> |
|
5 |
+ <version>1.0</version> |
|
6 |
+ |
|
7 |
+ <file name="$sourcedir/Subs-Editor.php"> |
|
8 |
+ <operation> |
|
9 |
+ <search position="replace"><![CDATA[ // Start with any testing. |
|
10 |
+ if ($do_test) |
|
11 |
+ { |
|
12 |
+ // This cannot happen! |
|
13 |
+ if (!isset($_SESSION[$verificationOptions['id'] . '_vv']['count'])) |
|
14 |
+ fatal_lang_error('no_access', false); |
|
15 |
+]]></search> |
|
16 |
+ <add><![CDATA[ // Start with any testing. |
|
17 |
+ if ($do_test) |
|
18 |
+ { |
|
19 |
+ // Check against SFS |
|
20 |
+ if (is_callable($smcFunc['classSFS'], 'checkRegisterPost')) |
|
21 |
+ $smcFunc['classSFS']->checkVerificationTest($thisVerification, $verification_errors); |
|
22 |
+ |
|
23 |
+ // This cannot happen! |
|
24 |
+ if (!isset($_SESSION[$verificationOptions['id'] . '_vv']['count'])) |
|
25 |
+ fatal_lang_error('no_access', false); |
|
26 |
+]]></add> |
|
27 |
+ </operation> |
|
28 |
+ </file> |
|
29 |
+</modification> |
|
0 | 30 |
\ No newline at end of file |
... | ... |
@@ -0,0 +1,77 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+/* The section Name */ |
|
4 |
+$txt['sfs_admin_area'] = 'Stop Forum Spam'; |
|
5 |
+$txt['sfs_admin_logs'] = 'SFS Logs'; |
|
6 |
+ |
|
7 |
+/* Admin Section General header */ |
|
8 |
+$txt['sfs_general_title'] = 'General Configuration'; |
|
9 |
+ |
|
10 |
+/* Admin section configuration options */ |
|
11 |
+$txt['sfs_enabled'] = 'Enable Stop Forum Spam?'; |
|
12 |
+$txt['sfs_log_debug'] = 'Enable Logging of all SFS requests (Debugging Only)?'; |
|
13 |
+$txt['sfs_ipcheck'] = 'Check IP Address?'; |
|
14 |
+$txt['sfs_usernamecheck'] = 'Check Username?'; |
|
15 |
+$txt['sfs_emailcheck'] = 'Check Email? (Recommended)'; |
|
16 |
+ |
|
17 |
+/* Admin section: Region Config */ |
|
18 |
+$txt['sfs_region'] = 'Geographic Access Region'; |
|
19 |
+$txt['sfs_region_global'] = 'Global (Recommended)'; |
|
20 |
+$txt['sfs_region_us'] = 'United States Region'; |
|
21 |
+$txt['sfs_region_eu'] = 'Europe Region'; |
|
22 |
+ |
|
23 |
+/* Admin section: Wildcard section */ |
|
24 |
+$txt['sfs_wildcard_email'] = 'Ignore Wildcard Email Checks'; |
|
25 |
+$txt['sfs_wildcard_username'] = 'Ignore Wildcard Username Checks'; |
|
26 |
+$txt['sfs_wildcard_ip'] = 'Ignore Wildcard IP Checks'; |
|
27 |
+ |
|
28 |
+/* Admin Section: Tor handling section */ |
|
29 |
+$txt['sfs_tor_check'] = 'TOR Exit Node Handling'; |
|
30 |
+$txt['sfs_tor_check_block'] = 'Block All Exit Nodes (Default)'; |
|
31 |
+$txt['sfs_tor_check_ignore'] = 'Ignore All Exit Nodes'; |
|
32 |
+$txt['sfs_tor_check_bad'] = 'Block Only Known Bad Exit Nodes'; |
|
33 |
+ |
|
34 |
+/* Admin Section: Verification Options header */ |
|
35 |
+$txt['sfs_verification_title'] = 'Verification Options'; |
|
36 |
+$txt['sfs_verification_desc'] = 'Usage of these options reuqire Anti-Spam Verification options to be setup and configurred. Disabling verification options or not requiring it in specific sections will override these options.'; |
|
37 |
+ |
|
38 |
+/* Admin Section: Verification Options for guests */ |
|
39 |
+$txt['sfs_verification_options'] = 'Guest Verification Sections'; |
|
40 |
+$txt['sfs_verification_options_post'] = 'Posting'; |
|
41 |
+$txt['sfs_verification_options_report'] = 'Reporting Topics'; |
|
42 |
+$txt['sfs_verification_options_search'] = 'Search (Not Recommended)'; |
|
43 |
+$txt['sfs_verification_options_extra'] = 'Extra sections'; |
|
44 |
+$txt['sfs_verification_options_extra_subtext'] = 'Used for other mods or areas that add additional sections using custom verification names. Use comma separted values. Use % for wildcards'; |
|
45 |
+ |
|
46 |
+$txt['sfs_verification_options_members'] = 'Member Verification Sections'; |
|
47 |
+$txt['sfs_verification_options_members_post_threshold'] = 'Post Count after which we stop these checks.'; |
|
48 |
+$txt['sfs_verification_options_membersextra'] = 'Extra sections'; |
|
49 |
+ |
|
50 |
+/* Request handling */ |
|
51 |
+$txt['sfs_request_failure'] = 'SFS Failed with invalid response'; |
|
52 |
+$txt['sfs_request_failure_nodata'] = 'SFS Failed as no data was sent'; |
|
53 |
+ |
|
54 |
+/* Spammer detection */ |
|
55 |
+$txt['sfs_request_blocked'] = 'Your request was denied as one or more emails, usernames, or IPs where found on the Stop Forum Spam blacklist'; |
|
56 |
+ |
|
57 |
+/* Admin Section Logs */ |
|
58 |
+$txt['sfs_log_no_entries_found'] = 'No Entries found in the SFS logs'; |
|
59 |
+$txt['sfs_log_search_member'] = 'Member'; |
|
60 |
+$txt['sfs_log_search_username'] = 'Username'; |
|
61 |
+$txt['sfs_log_search_email'] = 'Email'; |
|
62 |
+$txt['sfs_log_search_ip'] = 'IP Address'; |
|
63 |
+$txt['sfs_log_search_ip2'] = 'IP Address (Ban Check)'; |
|
64 |
+$txt['sfs_log_header_type'] = 'Log Type'; |
|
65 |
+$txt['sfs_log_header_time'] = 'Time'; |
|
66 |
+$txt['sfs_log_header_member'] = 'Member'; |
|
67 |
+$txt['sfs_log_header_username'] = 'Username'; |
|
68 |
+$txt['sfs_log_header_email'] = 'Email'; |
|
69 |
+$txt['sfs_log_header_ip'] = 'IP Address'; |
|
70 |
+$txt['sfs_log_header_ip2'] = 'IP Address (Ban Check)'; |
|
71 |
+$txt['sfs_log_checks'] = 'Checks'; |
|
72 |
+$txt['sfs_log_result'] = 'Results'; |
|
73 |
+$txt['sfs_log_search'] = 'Log Search'; |
|
74 |
+$txt['sfs_log_types_0'] = 'Debug'; |
|
75 |
+$txt['sfs_log_types_1'] = 'Username'; |
|
76 |
+$txt['sfs_log_types_2'] = 'Email'; |
|
77 |
+$txt['sfs_log_types_3'] = 'IP Address'; |
... | ... |
@@ -0,0 +1,76 @@ |
1 |
+<?xml version="1.0"?> |
|
2 |
+<!DOCTYPE package-info SYSTEM "http://www.simplemachines.org/xml/package-info"> |
|
3 |
+<package-info xmlns="http://www.simplemachines.org/xml/package-info" xmlns:smf="http://www.simplemachines.org/"> |
|
4 |
+ <id>SleePy:StopForumSpam</id> |
|
5 |
+ <name>Stop Forum Spam</name> |
|
6 |
+ <version>1.0</version> |
|
7 |
+ <type>modification</type> |
|
8 |
+ |
|
9 |
+ <install for="1.1.*"> |
|
10 |
+ <readme lang="english" parsebbc="true" type="inline">This mod is [b]not compatible[/b] with your version of SMF, it requires 2.0 or later.</readme> |
|
11 |
+ </install> |
|
12 |
+ |
|
13 |
+ <!-- 2.0 has no support for hooks --> |
|
14 |
+ <install for="2.0.*"> |
|
15 |
+ <database>install_sfs.php</database> |
|
16 |
+ <code type="file">sfs_hooks_install.php</code> |
|
17 |
+ <modification>install_smf20.xml</modification> |
|
18 |
+ |
|
19 |
+ <require-file name="language/StopForumSpam.english.php" destination="$themes_dir/default/languages" /> |
|
20 |
+ <require-file name="StopForumSpam.php" destination="$sourcedir" /> |
|
21 |
+ |
|
22 |
+ <redirect url="?action=admin;area=modsettings;sa=sfs" /> |
|
23 |
+ </install> |
|
24 |
+ |
|
25 |
+ <uninstall for="2.0.*"> |
|
26 |
+ <!-- database changes, undone --> |
|
27 |
+ <database>install_sfs.php</database> |
|
28 |
+ <code type="file">sfs_hooks_remove.php</code> |
|
29 |
+ |
|
30 |
+ <modification reverse="true">install_smf20.xml</modification> |
|
31 |
+ |
|
32 |
+ <!-- language files, removed --> |
|
33 |
+ <remove-dir name="$themes_dir/default/languages/StopForumSpam.english.php" /> |
|
34 |
+ |
|
35 |
+ <!-- source files, removed --> |
|
36 |
+ <remove-dir name="$sourcedir/StopForumSpam.php" /> |
|
37 |
+ </uninstall> |
|
38 |
+ |
|
39 |
+ <install for="2.1 RC3, 2.1.*"> |
|
40 |
+ <database>install_sfs.php</database> |
|
41 |
+ |
|
42 |
+ <require-file name="language/StopForumSpam.english.php" destination="$themes_dir/default/languages" /> |
|
43 |
+ <require-file name="StopForumSpam.php" destination="$sourcedir" /> |
|
44 |
+ |
|
45 |
+ <!-- All the hooks --> |
|
46 |
+ <hook hook="integrate_pre_include" function="$sourcedir/StopForumSpam.php" /> |
|
47 |
+ <hook hook="integrate_pre_load" function="SFS::hook_pre_load" /> |
|
48 |
+ <hook hook="integrate_admin_areas" function="SFS::hook_admin_areas" /> |
|
49 |
+ <hook hook="integrate_modify_modifications" function="SFS::hook_modify_modifications" /> |
|
50 |
+ <hook hook="integrate_register" function="SFS::hook_register" /> |
|
51 |
+ <hook hook="integrate_manage_logs" function="SFS::hook_manage_logs" /> |
|
52 |
+ |
|
53 |
+ <redirect url="?action=admin;area=securitysettings;sa=sfs" /> |
|
54 |
+ </install> |
|
55 |
+ |
|
56 |
+ <uninstall for="2.1 RC3, 2.1.*"> |
|
57 |
+ <!-- database changes, undone --> |
|
58 |
+ <database>install_sfs.php</database> |
|
59 |
+ <code type="file">uninstall-sd-required.php</code> |
|
60 |
+ |
|
61 |
+ <!-- All the hooks, removed --> |
|
62 |
+ <hook hook="integrate_pre_include" function="$sourcedir/StopForumSpam.php" reverse="true" /> |
|
63 |
+ <hook hook="integrate_pre_load" function="SFS::hook_pre_load" reverse="true" /> |
|
64 |
+ <hook hook="integrate_admin_areas" function="SFS::hook_admin_areas" reverse="true" /> |
|
65 |
+ <hook hook="integrate_modify_modifications" function="SFS::hook_modify_modifications" reverse="true" /> |
|
66 |
+ <hook hook="integrate_register" function="SFS::hook_register" reverse="true" /> |
|
67 |
+ <hook hook="integrate_manage_logs" function="SFS::hook_manage_logs" reverse="true" /> |
|
68 |
+ |
|
69 |
+ <!-- language files, removed --> |
|
70 |
+ <remove-dir name="$themes_dir/default/languages/StopForumSpam.english.php" /> |
|
71 |
+ |
|
72 |
+ <!-- source files, removed --> |
|
73 |
+ <remove-dir name="$sourcedir/StopForumSpam.php" /> |
|
74 |
+ </uninstall> |
|
75 |
+ |
|
76 |
+</package-info> |
|
0 | 77 |
\ No newline at end of file |
... | ... |
@@ -0,0 +1,24 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+// If we have found SSI.php and we are outside of SMF, then we are running standalone. |
|
4 |
+if (file_exists(dirname(__FILE__) . '/SSI.php') && !defined('SMF')) |
|
5 |
+ require_once(dirname(__FILE__) . '/SSI.php'); |
|
6 |
+elseif (file_exists(getcwd() . '/SSI.php') && !defined('SMF')) |
|
7 |
+ require_once(getcwd() . '/SSI.php'); |
|
8 |
+elseif (!defined('SMF')) // If we are outside SMF and can't find SSI.php, then throw an error |
|
9 |
+ die('<b>Error:</b> Cannot install - please verify you put this file in the same place as SMF\'s SSI.php.'); |
|
10 |
+ |
|
11 |
+if (SMF == 'SSI') |
|
12 |
+ db_extend('packages'); |
|
13 |
+ |
|
14 |
+$hooks = array( |
|
15 |
+ 'integrate_pre_include' => '$sourcedir/StopForumSpam.php', |
|
16 |
+ 'integrate_pre_load' => 'SFS::hook_pre_load', |
|
17 |
+ 'integrate_admin_areas' => 'SFS::hook_admin_areas', |
|
18 |
+ 'integrate_modify_modifications' => 'SFS::hook_modify_modifications', |
|
19 |
+ 'integrate_register' => 'SFS::hook_register', |
|
20 |
+ 'integrate_manage_logs' => 'SFS::hook_manage_logs' |
|
21 |
+); |
|
22 |
+ |
|
23 |
+foreach ($hooks as $hook => $func) |
|
24 |
+ add_integration_function($hook, $func, true); |
|
0 | 25 |
\ No newline at end of file |
... | ... |
@@ -0,0 +1,24 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+// If we have found SSI.php and we are outside of SMF, then we are running standalone. |
|
4 |
+if (file_exists(dirname(__FILE__) . '/SSI.php') && !defined('SMF')) |
|
5 |
+ require_once(dirname(__FILE__) . '/SSI.php'); |
|
6 |
+elseif (file_exists(getcwd() . '/SSI.php') && !defined('SMF')) |
|
7 |
+ require_once(getcwd() . '/SSI.php'); |
|
8 |
+elseif (!defined('SMF')) // If we are outside SMF and can't find SSI.php, then throw an error |
|
9 |
+ die('<b>Error:</b> Cannot install - please verify you put this file in the same place as SMF\'s SSI.php.'); |
|
10 |
+ |
|
11 |
+if (SMF == 'SSI') |
|
12 |
+ db_extend('packages'); |
|
13 |
+ |
|
14 |
+$hooks = array( |
|
15 |
+ 'integrate_pre_include' => '$sourcedir/StopForumSpam.php', |
|
16 |
+ 'integrate_pre_load' => 'SFS::hook_pre_load', |
|
17 |
+ 'integrate_admin_areas' => 'SFS::hook_admin_areas', |
|
18 |
+ 'integrate_modify_modifications' => 'SFS::hook_modify_modifications', |
|
19 |
+ 'integrate_register' => 'SFS::hook_register', |
|
20 |
+ 'integrate_manage_logs' => 'SFS::hook_manage_logs' |
|
21 |
+); |
|
22 |
+ |
|
23 |
+foreach ($hooks as $hook => $func) |
|
24 |
+ remove_integration_function($hook, $func); |
|
0 | 25 |
\ No newline at end of file |
1 | 26 |