|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* This file has functions in it to do with authentication, user handling, and the like. |
|
5
|
|
|
* |
|
6
|
|
|
* Simple Machines Forum (SMF) |
|
7
|
|
|
* |
|
8
|
|
|
* @package SMF |
|
9
|
|
|
* @author Simple Machines http://www.simplemachines.org |
|
10
|
|
|
* @copyright 2017 Simple Machines and individual contributors |
|
11
|
|
|
* @license http://www.simplemachines.org/about/smf/license.php BSD |
|
12
|
|
|
* |
|
13
|
|
|
* @version 2.1 Beta 4 |
|
14
|
|
|
*/ |
|
15
|
|
|
|
|
16
|
|
|
if (!defined('SMF')) |
|
17
|
|
|
die('No direct access...'); |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Sets the SMF-style login cookie and session based on the id_member and password passed. |
|
21
|
|
|
* - password should be already encrypted with the cookie salt. |
|
22
|
|
|
* - logs the user out if id_member is zero. |
|
23
|
|
|
* - sets the cookie and session to last the number of seconds specified by cookie_length. |
|
24
|
|
|
* - when logging out, if the globalCookies setting is enabled, attempts to clear the subdomain's cookie too. |
|
25
|
|
|
* |
|
26
|
|
|
* @param int $cookie_length How long the cookie should last (in minutes) |
|
27
|
|
|
* @param int $id The ID of the member to set the cookie for |
|
28
|
|
|
* @param string $password The hashed password |
|
29
|
|
|
*/ |
|
30
|
|
|
function setLoginCookie($cookie_length, $id, $password = '') |
|
31
|
|
|
{ |
|
32
|
|
|
global $smcFunc, $cookiename, $boardurl, $modSettings, $sourcedir; |
|
33
|
|
|
|
|
34
|
|
|
$id = (int) $id; |
|
35
|
|
|
|
|
36
|
|
|
// If changing state force them to re-address some permission caching. |
|
37
|
|
|
$_SESSION['mc']['time'] = 0; |
|
38
|
|
|
|
|
39
|
|
|
// The cookie may already exist, and have been set with different options. |
|
40
|
|
|
$cookie_state = (empty($modSettings['localCookies']) ? 0 : 1) | (empty($modSettings['globalCookies']) ? 0 : 2); |
|
41
|
|
|
if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\{i:0;i:\d{1,7};i:1;s:(0|128):"([a-fA-F0-9]{128})?";i:2;[id]:\d{1,14};(i:3;i:\d;)?\}$~', $_COOKIE[$cookiename]) === 1) |
|
42
|
|
|
{ |
|
43
|
|
|
$array = $smcFunc['json_decode']($_COOKIE[$cookiename], true); |
|
44
|
|
|
|
|
45
|
|
|
// Legacy format |
|
46
|
|
|
if (is_null($array)) |
|
47
|
|
|
$array = safe_unserialize($_COOKIE[$cookiename]); |
|
48
|
|
|
|
|
49
|
|
|
// Out with the old, in with the new! |
|
50
|
|
|
if (isset($array[3]) && $array[3] != $cookie_state) |
|
51
|
|
|
{ |
|
52
|
|
|
$cookie_url = url_parts($array[3] & 1 > 0, $array[3] & 2 > 0); |
|
53
|
|
|
smf_setcookie($cookiename, $smcFunc['json_encode'](array(0, '', 0)), time() - 3600, $cookie_url[1], $cookie_url[0]); |
|
54
|
|
|
} |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
// Get the data and path to set it on. |
|
58
|
|
|
$data = $smcFunc['json_encode'](empty($id) ? array(0, '', 0) : array($id, $password, time() + $cookie_length, $cookie_state)); |
|
59
|
|
|
$cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
|
60
|
|
|
|
|
61
|
|
|
// Set the cookie, $_COOKIE, and session variable. |
|
62
|
|
|
smf_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]); |
|
63
|
|
|
|
|
64
|
|
|
// If subdomain-independent cookies are on, unset the subdomain-dependent cookie too. |
|
65
|
|
View Code Duplication |
if (empty($id) && !empty($modSettings['globalCookies'])) |
|
|
|
|
|
|
66
|
|
|
smf_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], ''); |
|
67
|
|
|
|
|
68
|
|
|
// Any alias URLs? This is mainly for use with frames, etc. |
|
69
|
|
|
if (!empty($modSettings['forum_alias_urls'])) |
|
70
|
|
|
{ |
|
71
|
|
|
$aliases = explode(',', $modSettings['forum_alias_urls']); |
|
72
|
|
|
|
|
73
|
|
|
$temp = $boardurl; |
|
74
|
|
|
foreach ($aliases as $alias) |
|
75
|
|
|
{ |
|
76
|
|
|
// Fake the $boardurl so we can set a different cookie. |
|
77
|
|
|
$alias = strtr(trim($alias), array('http://' => '', 'https://' => '')); |
|
78
|
|
|
$boardurl = 'http://' . $alias; |
|
79
|
|
|
|
|
80
|
|
|
$cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
|
81
|
|
|
|
|
82
|
|
|
if ($cookie_url[0] == '') |
|
83
|
|
|
$cookie_url[0] = strtok($alias, '/'); |
|
84
|
|
|
|
|
85
|
|
|
smf_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]); |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
$boardurl = $temp; |
|
89
|
|
|
} |
|
90
|
|
|
|
|
91
|
|
|
$_COOKIE[$cookiename] = $data; |
|
92
|
|
|
|
|
93
|
|
|
// Make sure the user logs in with a new session ID. |
|
94
|
|
|
if (!isset($_SESSION['login_' . $cookiename]) || $_SESSION['login_' . $cookiename] !== $data) |
|
95
|
|
|
{ |
|
96
|
|
|
// We need to meddle with the session. |
|
97
|
|
|
require_once($sourcedir . '/Session.php'); |
|
98
|
|
|
|
|
99
|
|
|
// Backup and remove the old session. |
|
100
|
|
|
$oldSessionData = $_SESSION; |
|
101
|
|
|
$_SESSION = array(); |
|
102
|
|
|
session_destroy(); |
|
103
|
|
|
|
|
104
|
|
|
// Recreate and restore the new session. |
|
105
|
|
|
loadSession(); |
|
106
|
|
|
// @todo should we use session_regenerate_id(true); now that we are 5.1+ |
|
107
|
|
|
session_regenerate_id(); |
|
108
|
|
|
$_SESSION = $oldSessionData; |
|
109
|
|
|
|
|
110
|
|
|
$_SESSION['login_' . $cookiename] = $data; |
|
111
|
|
|
} |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
/** |
|
115
|
|
|
* Sets Two Factor Auth cookie |
|
116
|
|
|
* |
|
117
|
|
|
* @param int $cookie_length How long the cookie should last, in minutes |
|
118
|
|
|
* @param int $id The ID of the member |
|
119
|
|
|
* @param string $secret Should be a salted secret using hash_salt |
|
120
|
|
|
* @param bool $preserve Whether to preserve the cookie for 30 days |
|
121
|
|
|
*/ |
|
122
|
|
|
function setTFACookie($cookie_length, $id, $secret, $preserve = false) |
|
123
|
|
|
{ |
|
124
|
|
|
global $smcFunc, $modSettings, $cookiename; |
|
125
|
|
|
|
|
126
|
|
|
$identifier = $cookiename . '_tfa'; |
|
127
|
|
|
$cookie_state = (empty($modSettings['localCookies']) ? 0 : 1) | (empty($modSettings['globalCookies']) ? 0 : 2); |
|
128
|
|
|
|
|
129
|
|
|
if ($preserve) |
|
130
|
|
|
$cookie_length = 81600 * 30; |
|
131
|
|
|
|
|
132
|
|
|
// Get the data and path to set it on. |
|
133
|
|
|
$data = $smcFunc['json_encode'](empty($id) ? array(0, '', 0, $cookie_state, false) : array($id, $secret, time() + $cookie_length, $cookie_state, $preserve)); |
|
134
|
|
|
$cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
|
135
|
|
|
|
|
136
|
|
|
// Set the cookie, $_COOKIE, and session variable. |
|
137
|
|
|
smf_setcookie($identifier, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]); |
|
138
|
|
|
|
|
139
|
|
|
// If subdomain-independent cookies are on, unset the subdomain-dependent cookie too. |
|
140
|
|
View Code Duplication |
if (empty($id) && !empty($modSettings['globalCookies'])) |
|
|
|
|
|
|
141
|
|
|
smf_setcookie($identifier, $data, time() + $cookie_length, $cookie_url[1], ''); |
|
142
|
|
|
|
|
143
|
|
|
$_COOKIE[$identifier] = $data; |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
/** |
|
147
|
|
|
* Get the domain and path for the cookie |
|
148
|
|
|
* - normally, local and global should be the localCookies and globalCookies settings, respectively. |
|
149
|
|
|
* - uses boardurl to determine these two things. |
|
150
|
|
|
* |
|
151
|
|
|
* @param bool $local Whether we want local cookies |
|
152
|
|
|
* @param bool $global Whether we want global cookies |
|
153
|
|
|
* @return array An array to set the cookie on with domain and path in it, in that order |
|
154
|
|
|
*/ |
|
155
|
|
|
function url_parts($local, $global) |
|
156
|
|
|
{ |
|
157
|
|
|
global $boardurl, $modSettings; |
|
158
|
|
|
|
|
159
|
|
|
// Parse the URL with PHP to make life easier. |
|
160
|
|
|
$parsed_url = parse_url($boardurl); |
|
161
|
|
|
|
|
162
|
|
|
// Is local cookies off? |
|
163
|
|
|
if (empty($parsed_url['path']) || !$local) |
|
164
|
|
|
$parsed_url['path'] = ''; |
|
165
|
|
|
|
|
166
|
|
|
if (!empty($modSettings['globalCookiesDomain']) && strpos($boardurl, $modSettings['globalCookiesDomain']) !== false) |
|
167
|
|
|
$parsed_url['host'] = $modSettings['globalCookiesDomain']; |
|
168
|
|
|
|
|
169
|
|
|
// Globalize cookies across domains (filter out IP-addresses)? |
|
170
|
|
|
elseif ($global && preg_match('~^\d{1,3}(\.\d{1,3}){3}$~', $parsed_url['host']) == 0 && preg_match('~(?:[^\.]+\.)?([^\.]{2,}\..+)\z~i', $parsed_url['host'], $parts) == 1) |
|
171
|
|
|
$parsed_url['host'] = '.' . $parts[1]; |
|
172
|
|
|
|
|
173
|
|
|
// We shouldn't use a host at all if both options are off. |
|
174
|
|
|
elseif (!$local && !$global) |
|
175
|
|
|
$parsed_url['host'] = ''; |
|
176
|
|
|
|
|
177
|
|
|
// The host also shouldn't be set if there aren't any dots in it. |
|
178
|
|
|
elseif (!isset($parsed_url['host']) || strpos($parsed_url['host'], '.') === false) |
|
179
|
|
|
$parsed_url['host'] = ''; |
|
180
|
|
|
|
|
181
|
|
|
return array($parsed_url['host'], $parsed_url['path'] . '/'); |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* Throws guests out to the login screen when guest access is off. |
|
186
|
|
|
* - sets $_SESSION['login_url'] to $_SERVER['REQUEST_URL']. |
|
187
|
|
|
* - uses the 'kick_guest' sub template found in Login.template.php. |
|
188
|
|
|
*/ |
|
189
|
|
|
function KickGuest() |
|
190
|
|
|
{ |
|
191
|
|
|
global $txt, $context; |
|
192
|
|
|
|
|
193
|
|
|
loadLanguage('Login'); |
|
194
|
|
|
loadTemplate('Login'); |
|
195
|
|
|
createToken('login'); |
|
196
|
|
|
|
|
197
|
|
|
// Never redirect to an attachment |
|
198
|
|
View Code Duplication |
if (strpos($_SERVER['REQUEST_URL'], 'dlattach') === false) |
|
|
|
|
|
|
199
|
|
|
$_SESSION['login_url'] = $_SERVER['REQUEST_URL']; |
|
200
|
|
|
|
|
201
|
|
|
$context['sub_template'] = 'kick_guest'; |
|
202
|
|
|
$context['page_title'] = $txt['login']; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* Display a message about the forum being in maintenance mode. |
|
207
|
|
|
* - display a login screen with sub template 'maintenance'. |
|
208
|
|
|
* - sends a 503 header, so search engines don't bother indexing while we're in maintenance mode. |
|
209
|
|
|
*/ |
|
210
|
|
|
function InMaintenance() |
|
211
|
|
|
{ |
|
212
|
|
|
global $txt, $mtitle, $mmessage, $context, $smcFunc; |
|
213
|
|
|
|
|
214
|
|
|
loadLanguage('Login'); |
|
215
|
|
|
loadTemplate('Login'); |
|
216
|
|
|
createToken('login'); |
|
217
|
|
|
|
|
218
|
|
|
// Send a 503 header, so search engines don't bother indexing while we're in maintenance mode. |
|
219
|
|
|
header('HTTP/1.1 503 Service Temporarily Unavailable'); |
|
220
|
|
|
|
|
221
|
|
|
// Basic template stuff.. |
|
222
|
|
|
$context['sub_template'] = 'maintenance'; |
|
223
|
|
|
$context['title'] = $smcFunc['htmlspecialchars']($mtitle); |
|
224
|
|
|
$context['description'] = &$mmessage; |
|
225
|
|
|
$context['page_title'] = $txt['maintain_mode']; |
|
226
|
|
|
} |
|
227
|
|
|
|
|
228
|
|
|
/** |
|
229
|
|
|
* Question the verity of the admin by asking for his or her password. |
|
230
|
|
|
* - loads Login.template.php and uses the admin_login sub template. |
|
231
|
|
|
* - sends data to template so the admin is sent on to the page they |
|
232
|
|
|
* wanted if their password is correct, otherwise they can try again. |
|
233
|
|
|
* |
|
234
|
|
|
* @param string $type What login type is this - can be 'admin' or 'moderate' |
|
235
|
|
|
*/ |
|
236
|
|
|
function adminLogin($type = 'admin') |
|
237
|
|
|
{ |
|
238
|
|
|
global $context, $txt, $user_info; |
|
239
|
|
|
|
|
240
|
|
|
loadLanguage('Admin'); |
|
241
|
|
|
loadTemplate('Login'); |
|
242
|
|
|
|
|
243
|
|
|
// Validate what type of session check this is. |
|
244
|
|
|
$types = array(); |
|
245
|
|
|
call_integration_hook('integrate_validateSession', array(&$types)); |
|
246
|
|
|
$type = in_array($type, $types) || $type == 'moderate' ? $type : 'admin'; |
|
247
|
|
|
|
|
248
|
|
|
// They used a wrong password, log it and unset that. |
|
249
|
|
|
if (isset($_POST[$type . '_hash_pass']) || isset($_POST[$type . '_pass'])) |
|
250
|
|
|
{ |
|
251
|
|
|
$txt['security_wrong'] = sprintf($txt['security_wrong'], isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $txt['unknown'], $_SERVER['HTTP_USER_AGENT'], $user_info['ip']); |
|
252
|
|
|
log_error($txt['security_wrong'], 'critical'); |
|
253
|
|
|
|
|
254
|
|
|
if (isset($_POST[$type . '_hash_pass'])) |
|
255
|
|
|
unset($_POST[$type . '_hash_pass']); |
|
256
|
|
|
if (isset($_POST[$type . '_pass'])) |
|
257
|
|
|
unset($_POST[$type . '_pass']); |
|
258
|
|
|
|
|
259
|
|
|
$context['incorrect_password'] = true; |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
createToken('admin-login'); |
|
263
|
|
|
|
|
264
|
|
|
// Figure out the get data and post data. |
|
265
|
|
|
$context['get_data'] = '?' . construct_query_string($_GET); |
|
266
|
|
|
$context['post_data'] = ''; |
|
267
|
|
|
|
|
268
|
|
|
// Now go through $_POST. Make sure the session hash is sent. |
|
269
|
|
|
$_POST[$context['session_var']] = $context['session_id']; |
|
270
|
|
|
foreach ($_POST as $k => $v) |
|
271
|
|
|
$context['post_data'] .= adminLogin_outputPostVars($k, $v); |
|
272
|
|
|
|
|
273
|
|
|
// Now we'll use the admin_login sub template of the Login template. |
|
274
|
|
|
$context['sub_template'] = 'admin_login'; |
|
275
|
|
|
|
|
276
|
|
|
// And title the page something like "Login". |
|
277
|
|
|
if (!isset($context['page_title'])) |
|
278
|
|
|
$context['page_title'] = $txt['login']; |
|
279
|
|
|
|
|
280
|
|
|
// The type of action. |
|
281
|
|
|
$context['sessionCheckType'] = $type; |
|
282
|
|
|
|
|
283
|
|
|
obExit(); |
|
284
|
|
|
|
|
285
|
|
|
// We MUST exit at this point, because otherwise we CANNOT KNOW that the user is privileged. |
|
286
|
|
|
trigger_error('Hacking attempt...', E_USER_ERROR); |
|
287
|
|
|
} |
|
288
|
|
|
|
|
289
|
|
|
/** |
|
290
|
|
|
* Used by the adminLogin() function. |
|
291
|
|
|
* if 'value' is an array, the function is called recursively. |
|
292
|
|
|
* |
|
293
|
|
|
* @param string $k The keys |
|
294
|
|
|
* @param string $v The values |
|
295
|
|
|
* @return string 'hidden' HTML form fields, containing key-value-pairs |
|
296
|
|
|
*/ |
|
297
|
|
|
function adminLogin_outputPostVars($k, $v) |
|
298
|
|
|
{ |
|
299
|
|
|
global $smcFunc; |
|
300
|
|
|
|
|
301
|
|
|
if (!is_array($v)) |
|
302
|
|
|
return ' |
|
303
|
|
|
<input type="hidden" name="' . $smcFunc['htmlspecialchars']($k) . '" value="' . strtr($v, array('"' => '"', '<' => '<', '>' => '>')) . '">'; |
|
304
|
|
|
else |
|
305
|
|
|
{ |
|
306
|
|
|
$ret = ''; |
|
307
|
|
|
foreach ($v as $k2 => $v2) |
|
308
|
|
|
$ret .= adminLogin_outputPostVars($k . '[' . $k2 . ']', $v2); |
|
309
|
|
|
|
|
310
|
|
|
return $ret; |
|
311
|
|
|
} |
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
/** |
|
315
|
|
|
* Properly urlencodes a string to be used in a query |
|
316
|
|
|
* |
|
317
|
|
|
* @param string $get |
|
318
|
|
|
* @return string Our query string |
|
319
|
|
|
*/ |
|
320
|
|
|
function construct_query_string($get) |
|
321
|
|
|
{ |
|
322
|
|
|
global $scripturl; |
|
323
|
|
|
|
|
324
|
|
|
$query_string = ''; |
|
325
|
|
|
|
|
326
|
|
|
// Awww, darn. The $scripturl contains GET stuff! |
|
327
|
|
|
$q = strpos($scripturl, '?'); |
|
328
|
|
|
if ($q !== false) |
|
329
|
|
|
{ |
|
330
|
|
|
parse_str(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr(substr($scripturl, $q + 1), ';', '&')), $temp); |
|
331
|
|
|
|
|
332
|
|
|
foreach ($get as $k => $v) |
|
|
|
|
|
|
333
|
|
|
{ |
|
334
|
|
|
// Only if it's not already in the $scripturl! |
|
335
|
|
|
if (!isset($temp[$k])) |
|
336
|
|
|
$query_string .= urlencode($k) . '=' . urlencode($v) . ';'; |
|
337
|
|
|
// If it changed, put it out there, but with an ampersand. |
|
338
|
|
View Code Duplication |
elseif ($temp[$k] != $get[$k]) |
|
|
|
|
|
|
339
|
|
|
$query_string .= urlencode($k) . '=' . urlencode($v) . '&'; |
|
340
|
|
|
} |
|
341
|
|
|
} |
|
342
|
|
View Code Duplication |
else |
|
|
|
|
|
|
343
|
|
|
{ |
|
344
|
|
|
// Add up all the data from $_GET into get_data. |
|
345
|
|
|
foreach ($get as $k => $v) |
|
|
|
|
|
|
346
|
|
|
$query_string .= urlencode($k) . '=' . urlencode($v) . ';'; |
|
347
|
|
|
} |
|
348
|
|
|
|
|
349
|
|
|
$query_string = substr($query_string, 0, -1); |
|
350
|
|
|
return $query_string; |
|
351
|
|
|
} |
|
352
|
|
|
|
|
353
|
|
|
/** |
|
354
|
|
|
* Finds members by email address, username, or real name. |
|
355
|
|
|
* - searches for members whose username, display name, or e-mail address match the given pattern of array names. |
|
356
|
|
|
* - searches only buddies if buddies_only is set. |
|
357
|
|
|
* |
|
358
|
|
|
* @param array $names The names of members to search for |
|
359
|
|
|
* @param bool $use_wildcards Whether to use wildcards. Accepts wildcards ? and * in the pattern if true |
|
360
|
|
|
* @param bool $buddies_only Whether to only search for the user's buddies |
|
361
|
|
|
* @param int $max The maximum number of results |
|
362
|
|
|
* @return array An array containing information about the matching members |
|
363
|
|
|
*/ |
|
364
|
|
|
function findMembers($names, $use_wildcards = false, $buddies_only = false, $max = 500) |
|
365
|
|
|
{ |
|
366
|
|
|
global $scripturl, $user_info, $smcFunc; |
|
367
|
|
|
|
|
368
|
|
|
// If it's not already an array, make it one. |
|
369
|
|
|
if (!is_array($names)) |
|
370
|
|
|
$names = explode(',', $names); |
|
371
|
|
|
|
|
372
|
|
|
$maybe_email = false; |
|
373
|
|
|
foreach ($names as $i => $name) |
|
374
|
|
|
{ |
|
375
|
|
|
// Trim, and fix wildcards for each name. |
|
376
|
|
|
$names[$i] = trim($smcFunc['strtolower']($name)); |
|
377
|
|
|
|
|
378
|
|
|
$maybe_email |= strpos($name, '@') !== false; |
|
379
|
|
|
|
|
380
|
|
|
// Make it so standard wildcards will work. (* and ?) |
|
381
|
|
|
if ($use_wildcards) |
|
382
|
|
|
$names[$i] = strtr($names[$i], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '\'' => ''')); |
|
383
|
|
|
else |
|
384
|
|
|
$names[$i] = strtr($names[$i], array('\'' => ''')); |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
// What are we using to compare? |
|
388
|
|
|
$comparison = $use_wildcards ? 'LIKE' : '='; |
|
389
|
|
|
|
|
390
|
|
|
// Nothing found yet. |
|
391
|
|
|
$results = array(); |
|
392
|
|
|
|
|
393
|
|
|
// This ensures you can't search someones email address if you can't see it. |
|
394
|
|
|
if (($use_wildcards || $maybe_email) && allowedTo('moderate_forum')) |
|
395
|
|
|
$email_condition = ' |
|
396
|
|
|
OR (email_address ' . $comparison . ' \'' . implode('\') OR (email_address ' . $comparison . ' \'', $names) . '\')'; |
|
397
|
|
|
else |
|
398
|
|
|
$email_condition = ''; |
|
399
|
|
|
|
|
400
|
|
|
// Get the case of the columns right - but only if we need to as things like MySQL will go slow needlessly otherwise. |
|
401
|
|
|
$member_name = $smcFunc['db_case_sensitive'] ? 'LOWER(member_name)' : 'member_name'; |
|
402
|
|
|
$real_name = $smcFunc['db_case_sensitive'] ? 'LOWER(real_name)' : 'real_name'; |
|
403
|
|
|
|
|
404
|
|
|
// Search by username, display name, and email address. |
|
405
|
|
|
$request = $smcFunc['db_query']('', ' |
|
406
|
|
|
SELECT id_member, member_name, real_name, email_address |
|
407
|
|
|
FROM {db_prefix}members |
|
408
|
|
|
WHERE ({raw:member_name_search} |
|
409
|
|
|
OR {raw:real_name_search} {raw:email_condition}) |
|
410
|
|
|
' . ($buddies_only ? 'AND id_member IN ({array_int:buddy_list})' : '') . ' |
|
411
|
|
|
AND is_activated IN (1, 11) |
|
412
|
|
|
LIMIT {int:limit}', |
|
413
|
|
|
array( |
|
414
|
|
|
'buddy_list' => $user_info['buddies'], |
|
415
|
|
|
'member_name_search' => $member_name . ' ' . $comparison . ' \'' . implode('\' OR ' . $member_name . ' ' . $comparison . ' \'', $names) . '\'', |
|
416
|
|
|
'real_name_search' => $real_name . ' ' . $comparison . ' \'' . implode('\' OR ' . $real_name . ' ' . $comparison . ' \'', $names) . '\'', |
|
417
|
|
|
'email_condition' => $email_condition, |
|
418
|
|
|
'limit' => $max, |
|
419
|
|
|
) |
|
420
|
|
|
); |
|
421
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
422
|
|
|
{ |
|
423
|
|
|
$results[$row['id_member']] = array( |
|
424
|
|
|
'id' => $row['id_member'], |
|
425
|
|
|
'name' => $row['real_name'], |
|
426
|
|
|
'username' => $row['member_name'], |
|
427
|
|
|
'email' => allowedTo('moderate_forum') ? $row['email_address'] : '', |
|
428
|
|
|
'href' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
429
|
|
|
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' |
|
430
|
|
|
); |
|
431
|
|
|
} |
|
432
|
|
|
$smcFunc['db_free_result']($request); |
|
433
|
|
|
|
|
434
|
|
|
// Return all the results. |
|
435
|
|
|
return $results; |
|
436
|
|
|
} |
|
437
|
|
|
|
|
438
|
|
|
/** |
|
439
|
|
|
* Called by index.php?action=findmember. |
|
440
|
|
|
* - is used as a popup for searching members. |
|
441
|
|
|
* - uses sub template find_members of the Help template. |
|
442
|
|
|
* - also used to add members for PM's sent using wap2/imode protocol. |
|
443
|
|
|
*/ |
|
444
|
|
|
function JSMembers() |
|
445
|
|
|
{ |
|
446
|
|
|
global $context, $scripturl, $user_info, $smcFunc; |
|
447
|
|
|
|
|
448
|
|
|
checkSession('get'); |
|
449
|
|
|
|
|
450
|
|
|
// Why is this in the Help template, you ask? Well, erm... it helps you. Does that work? |
|
451
|
|
|
loadTemplate('Help'); |
|
452
|
|
|
|
|
453
|
|
|
$context['template_layers'] = array(); |
|
454
|
|
|
$context['sub_template'] = 'find_members'; |
|
455
|
|
|
|
|
456
|
|
|
if (isset($_REQUEST['search'])) |
|
457
|
|
|
$context['last_search'] = $smcFunc['htmlspecialchars']($_REQUEST['search'], ENT_QUOTES); |
|
458
|
|
|
else |
|
459
|
|
|
$_REQUEST['start'] = 0; |
|
460
|
|
|
|
|
461
|
|
|
// Allow the user to pass the input to be added to to the box. |
|
462
|
|
|
$context['input_box_name'] = isset($_REQUEST['input']) && preg_match('~^[\w-]+$~', $_REQUEST['input']) === 1 ? $_REQUEST['input'] : 'to'; |
|
463
|
|
|
|
|
464
|
|
|
// Take the delimiter over GET in case it's \n or something. |
|
465
|
|
|
$context['delimiter'] = isset($_REQUEST['delim']) ? ($_REQUEST['delim'] == 'LB' ? "\n" : $_REQUEST['delim']) : ', '; |
|
466
|
|
|
$context['quote_results'] = !empty($_REQUEST['quote']); |
|
467
|
|
|
|
|
468
|
|
|
// List all the results. |
|
469
|
|
|
$context['results'] = array(); |
|
470
|
|
|
|
|
471
|
|
|
// Some buddy related settings ;) |
|
472
|
|
|
$context['show_buddies'] = !empty($user_info['buddies']); |
|
473
|
|
|
$context['buddy_search'] = isset($_REQUEST['buddies']); |
|
474
|
|
|
|
|
475
|
|
|
// If the user has done a search, well - search. |
|
476
|
|
|
if (isset($_REQUEST['search'])) |
|
477
|
|
|
{ |
|
478
|
|
|
$_REQUEST['search'] = $smcFunc['htmlspecialchars']($_REQUEST['search'], ENT_QUOTES); |
|
479
|
|
|
|
|
480
|
|
|
$context['results'] = findMembers(array($_REQUEST['search']), true, $context['buddy_search']); |
|
481
|
|
|
$total_results = count($context['results']); |
|
482
|
|
|
|
|
483
|
|
|
$context['page_index'] = constructPageIndex($scripturl . '?action=findmember;search=' . $context['last_search'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';input=' . $context['input_box_name'] . ($context['quote_results'] ? ';quote=1' : '') . ($context['buddy_search'] ? ';buddies' : ''), $_REQUEST['start'], $total_results, 7); |
|
484
|
|
|
|
|
485
|
|
|
// Determine the navigation context. |
|
486
|
|
|
$base_url = $scripturl . '?action=findmember;search=' . urlencode($context['last_search']) . (empty($_REQUEST['u']) ? '' : ';u=' . $_REQUEST['u']) . ';' . $context['session_var'] . '=' . $context['session_id']; |
|
487
|
|
|
$context['links'] = array( |
|
488
|
|
|
'first' => $_REQUEST['start'] >= 7 ? $base_url . ';start=0' : '', |
|
489
|
|
|
'prev' => $_REQUEST['start'] >= 7 ? $base_url . ';start=' . ($_REQUEST['start'] - 7) : '', |
|
490
|
|
|
'next' => $_REQUEST['start'] + 7 < $total_results ? $base_url . ';start=' . ($_REQUEST['start'] + 7) : '', |
|
491
|
|
|
'last' => $_REQUEST['start'] + 7 < $total_results ? $base_url . ';start=' . (floor(($total_results - 1) / 7) * 7) : '', |
|
492
|
|
|
'up' => $scripturl . '?action=pm;sa=send' . (empty($_REQUEST['u']) ? '' : ';u=' . $_REQUEST['u']), |
|
493
|
|
|
); |
|
494
|
|
|
$context['page_info'] = array( |
|
495
|
|
|
'current_page' => $_REQUEST['start'] / 7 + 1, |
|
496
|
|
|
'num_pages' => floor(($total_results - 1) / 7) + 1 |
|
497
|
|
|
); |
|
498
|
|
|
|
|
499
|
|
|
$context['results'] = array_slice($context['results'], $_REQUEST['start'], 7); |
|
500
|
|
|
} |
|
501
|
|
|
else |
|
502
|
|
|
$context['links']['up'] = $scripturl . '?action=pm;sa=send' . (empty($_REQUEST['u']) ? '' : ';u=' . $_REQUEST['u']); |
|
503
|
|
|
} |
|
504
|
|
|
|
|
505
|
|
|
/** |
|
506
|
|
|
* Outputs each member name on its own line. |
|
507
|
|
|
* - used by javascript to find members matching the request. |
|
508
|
|
|
*/ |
|
509
|
|
|
function RequestMembers() |
|
510
|
|
|
{ |
|
511
|
|
|
global $user_info, $txt, $smcFunc; |
|
512
|
|
|
|
|
513
|
|
|
checkSession('get'); |
|
514
|
|
|
|
|
515
|
|
|
$_REQUEST['search'] = $smcFunc['htmlspecialchars']($_REQUEST['search']) . '*'; |
|
516
|
|
|
$_REQUEST['search'] = trim($smcFunc['strtolower']($_REQUEST['search'])); |
|
517
|
|
|
$_REQUEST['search'] = strtr($_REQUEST['search'], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '&' => '&')); |
|
518
|
|
|
|
|
519
|
|
|
if (function_exists('iconv')) |
|
520
|
|
|
header('Content-Type: text/plain; charset=UTF-8'); |
|
521
|
|
|
|
|
522
|
|
|
$request = $smcFunc['db_query']('', ' |
|
523
|
|
|
SELECT real_name |
|
524
|
|
|
FROM {db_prefix}members |
|
525
|
|
|
WHERE {raw:real_name} LIKE {string:search}' . (isset($_REQUEST['buddies']) ? ' |
|
526
|
|
|
AND id_member IN ({array_int:buddy_list})' : '') . ' |
|
527
|
|
|
AND is_activated IN (1, 11) |
|
528
|
|
|
LIMIT ' . ($smcFunc['strlen']($_REQUEST['search']) <= 2 ? '100' : '800'), |
|
529
|
|
|
array( |
|
530
|
|
|
'real_name' => $smcFunc['db_case_sensitive'] ? 'LOWER(real_name)' : 'real_name', |
|
531
|
|
|
'buddy_list' => $user_info['buddies'], |
|
532
|
|
|
'search' => $_REQUEST['search'], |
|
533
|
|
|
) |
|
534
|
|
|
); |
|
535
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
536
|
|
|
{ |
|
537
|
|
|
if (function_exists('iconv')) |
|
538
|
|
|
{ |
|
539
|
|
|
$utf8 = iconv($txt['lang_character_set'], 'UTF-8', $row['real_name']); |
|
540
|
|
|
if ($utf8) |
|
541
|
|
|
$row['real_name'] = $utf8; |
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
$row['real_name'] = strtr($row['real_name'], array('&' => '&', '<' => '<', '>' => '>', '"' => '"')); |
|
545
|
|
|
|
|
546
|
|
|
if (preg_match('~&#\d+;~', $row['real_name']) != 0) |
|
547
|
|
|
$row['real_name'] = preg_replace_callback('~&#(\d+);~', 'fixchar__callback', $row['real_name']); |
|
548
|
|
|
|
|
549
|
|
|
echo $row['real_name'], "\n"; |
|
550
|
|
|
} |
|
551
|
|
|
$smcFunc['db_free_result']($request); |
|
552
|
|
|
|
|
553
|
|
|
obExit(false); |
|
554
|
|
|
} |
|
555
|
|
|
|
|
556
|
|
|
/** |
|
557
|
|
|
* Generates a random password for a user and emails it to them. |
|
558
|
|
|
* - called by Profile.php when changing someone's username. |
|
559
|
|
|
* - checks the validity of the new username. |
|
560
|
|
|
* - generates and sets a new password for the given user. |
|
561
|
|
|
* - mails the new password to the email address of the user. |
|
562
|
|
|
* - if username is not set, only a new password is generated and sent. |
|
563
|
|
|
* |
|
564
|
|
|
* @param int $memID The ID of the member |
|
565
|
|
|
* @param string $username The new username. If set, also checks the validity of the username |
|
566
|
|
|
*/ |
|
567
|
|
|
function resetPassword($memID, $username = null) |
|
568
|
|
|
{ |
|
569
|
|
|
global $sourcedir, $modSettings, $smcFunc, $language; |
|
570
|
|
|
|
|
571
|
|
|
// Language... and a required file. |
|
572
|
|
|
loadLanguage('Login'); |
|
573
|
|
|
require_once($sourcedir . '/Subs-Post.php'); |
|
574
|
|
|
|
|
575
|
|
|
// Get some important details. |
|
576
|
|
|
$request = $smcFunc['db_query']('', ' |
|
577
|
|
|
SELECT member_name, email_address, lngfile |
|
578
|
|
|
FROM {db_prefix}members |
|
579
|
|
|
WHERE id_member = {int:id_member}', |
|
580
|
|
|
array( |
|
581
|
|
|
'id_member' => $memID, |
|
582
|
|
|
) |
|
583
|
|
|
); |
|
584
|
|
|
list ($user, $email, $lngfile) = $smcFunc['db_fetch_row']($request); |
|
585
|
|
|
$smcFunc['db_free_result']($request); |
|
586
|
|
|
|
|
587
|
|
|
if ($username !== null) |
|
588
|
|
|
{ |
|
589
|
|
|
$old_user = $user; |
|
590
|
|
|
$user = trim($username); |
|
591
|
|
|
} |
|
592
|
|
|
|
|
593
|
|
|
// Generate a random password. |
|
594
|
|
|
$newPassword = substr(preg_replace('/\W/', '', md5(mt_rand())), 0, 10); |
|
595
|
|
|
$newPassword_sha1 = hash_password($user, $newPassword); |
|
596
|
|
|
|
|
597
|
|
|
// Do some checks on the username if needed. |
|
598
|
|
|
if ($username !== null) |
|
599
|
|
|
{ |
|
600
|
|
|
validateUsername($memID, $user); |
|
601
|
|
|
|
|
602
|
|
|
// Update the database... |
|
603
|
|
|
updateMemberData($memID, array('member_name' => $user, 'passwd' => $newPassword_sha1)); |
|
604
|
|
|
} |
|
605
|
|
|
else |
|
606
|
|
|
updateMemberData($memID, array('passwd' => $newPassword_sha1)); |
|
607
|
|
|
|
|
608
|
|
|
call_integration_hook('integrate_reset_pass', array($old_user, $user, $newPassword)); |
|
|
|
|
|
|
609
|
|
|
|
|
610
|
|
|
$replacements = array( |
|
611
|
|
|
'USERNAME' => $user, |
|
612
|
|
|
'PASSWORD' => $newPassword, |
|
613
|
|
|
); |
|
614
|
|
|
|
|
615
|
|
|
$emaildata = loadEmailTemplate('change_password', $replacements, empty($lngfile) || empty($modSettings['userLanguage']) ? $language : $lngfile); |
|
616
|
|
|
|
|
617
|
|
|
// Send them the email informing them of the change - then we're done! |
|
618
|
|
|
sendmail($email, $emaildata['subject'], $emaildata['body'], null, 'chgpass' . $memID, $emaildata['is_html'], 0); |
|
619
|
|
|
} |
|
620
|
|
|
|
|
621
|
|
|
/** |
|
622
|
|
|
* Checks a username obeys a load of rules |
|
623
|
|
|
* |
|
624
|
|
|
* @param int $memID The ID of the member |
|
625
|
|
|
* @param string $username The username to validate |
|
626
|
|
|
* @param boolean $return_error Whether to return errors |
|
627
|
|
|
* @param boolean $check_reserved_name Whether to check this against the list of reserved names |
|
628
|
|
|
* @return array|null Null if there are no errors, otherwise an array of errors if return_error is true |
|
629
|
|
|
*/ |
|
630
|
|
|
function validateUsername($memID, $username, $return_error = false, $check_reserved_name = true) |
|
631
|
|
|
{ |
|
632
|
|
|
global $sourcedir, $txt, $smcFunc, $user_info; |
|
633
|
|
|
|
|
634
|
|
|
$errors = array(); |
|
635
|
|
|
|
|
636
|
|
|
// Don't use too long a name. |
|
637
|
|
|
if ($smcFunc['strlen']($username) > 25) |
|
638
|
|
|
$errors[] = array('lang', 'error_long_name'); |
|
639
|
|
|
|
|
640
|
|
|
// No name?! How can you register with no name? |
|
641
|
|
|
if ($username == '') |
|
642
|
|
|
$errors[] = array('lang', 'need_username'); |
|
643
|
|
|
|
|
644
|
|
|
// Only these characters are permitted. |
|
645
|
|
|
if (in_array($username, array('_', '|')) || preg_match('~[<>&"\'=\\\\]~', preg_replace('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', '', $username)) != 0 || strpos($username, '[code') !== false || strpos($username, '[/code') !== false) |
|
646
|
|
|
$errors[] = array('lang', 'error_invalid_characters_username'); |
|
647
|
|
|
|
|
648
|
|
|
if (stristr($username, $txt['guest_title']) !== false) |
|
649
|
|
|
$errors[] = array('lang', 'username_reserved', 'general', array($txt['guest_title'])); |
|
650
|
|
|
|
|
651
|
|
|
if ($check_reserved_name) |
|
652
|
|
|
{ |
|
653
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
|
654
|
|
|
if (isReservedName($username, $memID, false)) |
|
655
|
|
|
$errors[] = array('done', '(' . $smcFunc['htmlspecialchars']($username) . ') ' . $txt['name_in_use']); |
|
656
|
|
|
} |
|
657
|
|
|
|
|
658
|
|
|
if ($return_error) |
|
659
|
|
|
return $errors; |
|
660
|
|
|
elseif (empty($errors)) |
|
661
|
|
|
return null; |
|
662
|
|
|
|
|
663
|
|
|
loadLanguage('Errors'); |
|
664
|
|
|
$error = $errors[0]; |
|
665
|
|
|
|
|
666
|
|
|
$message = $error[0] == 'lang' ? (empty($error[3]) ? $txt[$error[1]] : vsprintf($txt[$error[1]], $error[3])) : $error[1]; |
|
667
|
|
|
fatal_error($message, empty($error[2]) || $user_info['is_admin'] ? false : $error[2]); |
|
668
|
|
|
} |
|
669
|
|
|
|
|
670
|
|
|
/** |
|
671
|
|
|
* Checks whether a password meets the current forum rules |
|
672
|
|
|
* - called when registering/choosing a password. |
|
673
|
|
|
* - checks the password obeys the current forum settings for password strength. |
|
674
|
|
|
* - if password checking is enabled, will check that none of the words in restrict_in appear in the password. |
|
675
|
|
|
* - returns an error identifier if the password is invalid, or null. |
|
676
|
|
|
* |
|
677
|
|
|
* @param string $password The desired password |
|
678
|
|
|
* @param string $username The username |
|
679
|
|
|
* @param array $restrict_in An array of restricted strings that cannot be part of the password (email address, username, etc.) |
|
680
|
|
|
* @return null|string Null if valid or a string indicating what the problem was |
|
681
|
|
|
*/ |
|
682
|
|
|
function validatePassword($password, $username, $restrict_in = array()) |
|
683
|
|
|
{ |
|
684
|
|
|
global $modSettings, $smcFunc; |
|
685
|
|
|
|
|
686
|
|
|
// Perform basic requirements first. |
|
687
|
|
|
if ($smcFunc['strlen']($password) < (empty($modSettings['password_strength']) ? 4 : 8)) |
|
688
|
|
|
return 'short'; |
|
689
|
|
|
|
|
690
|
|
|
// Is this enough? |
|
691
|
|
|
if (empty($modSettings['password_strength'])) |
|
692
|
|
|
return null; |
|
693
|
|
|
|
|
694
|
|
|
// Otherwise, perform the medium strength test - checking if password appears in the restricted string. |
|
695
|
|
|
if (preg_match('~\b' . preg_quote($password, '~') . '\b~', implode(' ', $restrict_in)) != 0) |
|
696
|
|
|
return 'restricted_words'; |
|
697
|
|
|
elseif ($smcFunc['strpos']($password, $username) !== false) |
|
698
|
|
|
return 'restricted_words'; |
|
699
|
|
|
|
|
700
|
|
|
// If just medium, we're done. |
|
701
|
|
|
if ($modSettings['password_strength'] == 1) |
|
702
|
|
|
return null; |
|
703
|
|
|
|
|
704
|
|
|
// Otherwise, hard test next, check for numbers and letters, uppercase too. |
|
705
|
|
|
$good = preg_match('~(\D\d|\d\D)~', $password) != 0; |
|
706
|
|
|
$good &= $smcFunc['strtolower']($password) != $password; |
|
707
|
|
|
|
|
708
|
|
|
return $good ? null : 'chars'; |
|
709
|
|
|
} |
|
710
|
|
|
|
|
711
|
|
|
/** |
|
712
|
|
|
* Quickly find out what moderation authority this user has |
|
713
|
|
|
* - builds the moderator, group and board level querys for the user |
|
714
|
|
|
* - stores the information on the current users moderation powers in $user_info['mod_cache'] and $_SESSION['mc'] |
|
715
|
|
|
*/ |
|
716
|
|
|
function rebuildModCache() |
|
717
|
|
|
{ |
|
718
|
|
|
global $user_info, $smcFunc; |
|
719
|
|
|
|
|
720
|
|
|
// What groups can they moderate? |
|
721
|
|
|
$group_query = allowedTo('manage_membergroups') ? '1=1' : '0=1'; |
|
722
|
|
|
|
|
723
|
|
|
if ($group_query == '0=1' && !$user_info['is_guest']) |
|
724
|
|
|
{ |
|
725
|
|
|
$request = $smcFunc['db_query']('', ' |
|
726
|
|
|
SELECT id_group |
|
727
|
|
|
FROM {db_prefix}group_moderators |
|
728
|
|
|
WHERE id_member = {int:current_member}', |
|
729
|
|
|
array( |
|
730
|
|
|
'current_member' => $user_info['id'], |
|
731
|
|
|
) |
|
732
|
|
|
); |
|
733
|
|
|
$groups = array(); |
|
734
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
735
|
|
|
$groups[] = $row['id_group']; |
|
736
|
|
|
$smcFunc['db_free_result']($request); |
|
737
|
|
|
|
|
738
|
|
|
if (empty($groups)) |
|
739
|
|
|
$group_query = '0=1'; |
|
740
|
|
|
else |
|
741
|
|
|
$group_query = 'id_group IN (' . implode(',', $groups) . ')'; |
|
742
|
|
|
} |
|
743
|
|
|
|
|
744
|
|
|
// Then, same again, just the boards this time! |
|
745
|
|
|
$board_query = allowedTo('moderate_forum') ? '1=1' : '0=1'; |
|
746
|
|
|
|
|
747
|
|
|
if ($board_query == '0=1' && !$user_info['is_guest']) |
|
748
|
|
|
{ |
|
749
|
|
|
$boards = boardsAllowedTo('moderate_board', true); |
|
750
|
|
|
|
|
751
|
|
|
if (empty($boards)) |
|
752
|
|
|
$board_query = '0=1'; |
|
753
|
|
|
else |
|
754
|
|
|
$board_query = 'id_board IN (' . implode(',', $boards) . ')'; |
|
755
|
|
|
} |
|
756
|
|
|
|
|
757
|
|
|
// What boards are they the moderator of? |
|
758
|
|
|
$boards_mod = array(); |
|
759
|
|
|
if (!$user_info['is_guest']) |
|
760
|
|
|
{ |
|
761
|
|
|
$request = $smcFunc['db_query']('', ' |
|
762
|
|
|
SELECT id_board |
|
763
|
|
|
FROM {db_prefix}moderators |
|
764
|
|
|
WHERE id_member = {int:current_member}', |
|
765
|
|
|
array( |
|
766
|
|
|
'current_member' => $user_info['id'], |
|
767
|
|
|
) |
|
768
|
|
|
); |
|
769
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
770
|
|
|
$boards_mod[] = $row['id_board']; |
|
771
|
|
|
$smcFunc['db_free_result']($request); |
|
772
|
|
|
|
|
773
|
|
|
// Can any of the groups they're in moderate any of the boards? |
|
774
|
|
|
$request = $smcFunc['db_query']('', ' |
|
775
|
|
|
SELECT id_board |
|
776
|
|
|
FROM {db_prefix}moderator_groups |
|
777
|
|
|
WHERE id_group IN({array_int:groups})', |
|
778
|
|
|
array( |
|
779
|
|
|
'groups' => $user_info['groups'], |
|
780
|
|
|
) |
|
781
|
|
|
); |
|
782
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
|
783
|
|
|
$boards_mod[] = $row['id_board']; |
|
784
|
|
|
$smcFunc['db_free_result']($request); |
|
785
|
|
|
|
|
786
|
|
|
// Just in case we've got duplicates here... |
|
787
|
|
|
$boards_mod = array_unique($boards_mod); |
|
788
|
|
|
} |
|
789
|
|
|
|
|
790
|
|
|
$mod_query = empty($boards_mod) ? '0=1' : 'b.id_board IN (' . implode(',', $boards_mod) . ')'; |
|
791
|
|
|
|
|
792
|
|
|
$_SESSION['mc'] = array( |
|
793
|
|
|
'time' => time(), |
|
794
|
|
|
// This looks a bit funny but protects against the login redirect. |
|
795
|
|
|
'id' => $user_info['id'] && $user_info['name'] ? $user_info['id'] : 0, |
|
796
|
|
|
// If you change the format of 'gq' and/or 'bq' make sure to adjust 'can_mod' in Load.php. |
|
797
|
|
|
'gq' => $group_query, |
|
798
|
|
|
'bq' => $board_query, |
|
799
|
|
|
'ap' => boardsAllowedTo('approve_posts'), |
|
800
|
|
|
'mb' => $boards_mod, |
|
801
|
|
|
'mq' => $mod_query, |
|
802
|
|
|
); |
|
803
|
|
|
call_integration_hook('integrate_mod_cache'); |
|
804
|
|
|
|
|
805
|
|
|
$user_info['mod_cache'] = $_SESSION['mc']; |
|
806
|
|
|
|
|
807
|
|
|
// Might as well clean up some tokens while we are at it. |
|
808
|
|
|
cleanTokens(); |
|
809
|
|
|
} |
|
810
|
|
|
|
|
811
|
|
|
/** |
|
812
|
|
|
* The same thing as setcookie but gives support for HTTP-Only cookies in PHP < 5.2 |
|
813
|
|
|
* @todo We can remove this since SMF requires PHP >= 5.3.8 now |
|
814
|
|
|
* |
|
815
|
|
|
* @param string $name |
|
816
|
|
|
* @param string $value = '' |
|
817
|
|
|
* @param int $expire = 0 |
|
818
|
|
|
* @param string $path = '' |
|
819
|
|
|
* @param string $domain = '' |
|
820
|
|
|
* @param bool $secure = false |
|
821
|
|
|
* @param bool $httponly = true |
|
822
|
|
|
*/ |
|
823
|
|
|
function smf_setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = null, $httponly = true) |
|
824
|
|
|
{ |
|
825
|
|
|
global $modSettings; |
|
826
|
|
|
|
|
827
|
|
|
// In case a customization wants to override the default settings |
|
828
|
|
|
if ($httponly === null) |
|
829
|
|
|
$httponly = !empty($modSettings['httponlyCookies']); |
|
830
|
|
|
if ($secure === null) |
|
831
|
|
|
$secure = !empty($modSettings['secureCookies']); |
|
832
|
|
|
|
|
833
|
|
|
// Intercept cookie? |
|
834
|
|
|
call_integration_hook('integrate_cookie', array($name, $value, $expire, $path, $domain, $secure, $httponly)); |
|
835
|
|
|
|
|
836
|
|
|
// This function is pointless if we have PHP >= 5.2. |
|
837
|
|
|
return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly); |
|
838
|
|
|
} |
|
839
|
|
|
|
|
840
|
|
|
/** |
|
841
|
|
|
* Hashes username with password |
|
842
|
|
|
* |
|
843
|
|
|
* @param string $username The username |
|
844
|
|
|
* @param string $password The unhashed password |
|
845
|
|
|
* @param int $cost The cost |
|
846
|
|
|
* @return string The hashed password |
|
847
|
|
|
*/ |
|
848
|
|
|
function hash_password($username, $password, $cost = null) |
|
849
|
|
|
{ |
|
850
|
|
|
global $sourcedir, $smcFunc, $modSettings; |
|
851
|
|
|
if (!function_exists('password_hash')) |
|
852
|
|
|
require_once($sourcedir . '/Subs-Password.php'); |
|
853
|
|
|
|
|
854
|
|
|
$cost = empty($cost) ? (empty($modSettings['bcrypt_hash_cost']) ? 10 : $modSettings['bcrypt_hash_cost']) : $cost; |
|
855
|
|
|
|
|
856
|
|
|
return password_hash($smcFunc['strtolower']($username) . $password, PASSWORD_BCRYPT, array( |
|
857
|
|
|
'cost' => $cost, |
|
858
|
|
|
)); |
|
859
|
|
|
} |
|
860
|
|
|
|
|
861
|
|
|
/** |
|
862
|
|
|
* Hashes password with salt, this is solely used for cookies. |
|
863
|
|
|
* |
|
864
|
|
|
* @param string $password The password |
|
865
|
|
|
* @param string $salt The salt |
|
866
|
|
|
* @return string The hashed password |
|
867
|
|
|
*/ |
|
868
|
|
|
function hash_salt($password, $salt) |
|
869
|
|
|
{ |
|
870
|
|
|
return hash('sha512', $password . $salt); |
|
871
|
|
|
} |
|
872
|
|
|
|
|
873
|
|
|
/** |
|
874
|
|
|
* Verifies a raw SMF password against the bcrypt'd string |
|
875
|
|
|
* |
|
876
|
|
|
* @param string $username The username |
|
877
|
|
|
* @param string $password The password |
|
878
|
|
|
* @param string $hash The hashed string |
|
879
|
|
|
* @return bool Whether the hashed password matches the string |
|
880
|
|
|
*/ |
|
881
|
|
|
function hash_verify_password($username, $password, $hash) |
|
882
|
|
|
{ |
|
883
|
|
|
global $sourcedir, $smcFunc; |
|
884
|
|
|
if (!function_exists('password_verify')) |
|
885
|
|
|
require_once($sourcedir . '/Subs-Password.php'); |
|
886
|
|
|
|
|
887
|
|
|
return password_verify($smcFunc['strtolower']($username) . $password, $hash); |
|
888
|
|
|
} |
|
889
|
|
|
|
|
890
|
|
|
/** |
|
891
|
|
|
* Returns the length for current hash |
|
892
|
|
|
* |
|
893
|
|
|
* @return int The length for the current hash |
|
894
|
|
|
*/ |
|
895
|
|
|
function hash_length() |
|
896
|
|
|
{ |
|
897
|
|
|
return 60; |
|
898
|
|
|
} |
|
899
|
|
|
|
|
900
|
|
|
/** |
|
901
|
|
|
* Benchmarks the server to figure out an appropriate cost factor (minimum 9) |
|
902
|
|
|
* |
|
903
|
|
|
* @param float $hashTime Time to target, in seconds |
|
904
|
|
|
* @return int The cost |
|
905
|
|
|
*/ |
|
906
|
|
|
function hash_benchmark($hashTime = 0.2) |
|
907
|
|
|
{ |
|
908
|
|
|
$cost = 9; |
|
909
|
|
|
do { |
|
910
|
|
|
$timeStart = microtime(true); |
|
911
|
|
|
hash_password('test', 'thisisatestpassword', $cost); |
|
912
|
|
|
$timeTaken = microtime(true) - $timeStart; |
|
913
|
|
|
$cost++; |
|
914
|
|
|
} while ($timeTaken < $hashTime); |
|
915
|
|
|
|
|
916
|
|
|
return $cost; |
|
917
|
|
|
} |
|
918
|
|
|
|
|
919
|
|
|
?> |
|
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.