| Conditions | 89 |
| Paths | > 20000 |
| Total Lines | 338 |
| Code Lines | 155 |
| Lines | 35 |
| Ratio | 10.36 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php |
||
| 80 | function Login2() |
||
| 81 | { |
||
| 82 | global $txt, $scripturl, $user_info, $user_settings, $smcFunc; |
||
| 83 | global $cookiename, $modSettings, $context, $sourcedir, $maintenance; |
||
| 84 | |||
| 85 | // Check to ensure we're forcing SSL for authentication |
||
| 86 | View Code Duplication | if (!empty($modSettings['force_ssl']) && empty($maintenance) && (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on')) |
|
| 87 | fatal_lang_error('login_ssl_required'); |
||
| 88 | |||
| 89 | // Load cookie authentication stuff. |
||
| 90 | require_once($sourcedir . '/Subs-Auth.php'); |
||
| 91 | |||
| 92 | View Code Duplication | if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') |
|
| 93 | { |
||
| 94 | $context['from_ajax'] = true; |
||
| 95 | $context['template_layers'] = array(); |
||
| 96 | } |
||
| 97 | |||
| 98 | if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest']) |
||
| 99 | { |
||
| 100 | 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) |
||
| 101 | { |
||
| 102 | list (,, $timeout) = smf_json_decode($_COOKIE[$cookiename], true); |
||
| 103 | |||
| 104 | // That didn't work... Maybe it's using serialize? |
||
| 105 | if (is_null($timeout)) |
||
| 106 | list (,, $timeout) = safe_unserialize($_COOKIE[$cookiename]); |
||
| 107 | } |
||
| 108 | elseif (isset($_SESSION['login_' . $cookiename])) |
||
| 109 | { |
||
| 110 | list (,, $timeout) = smf_json_decode($_SESSION['login_' . $cookiename]); |
||
| 111 | |||
| 112 | // Try for old format |
||
| 113 | if (is_null($timeout)) |
||
| 114 | list (,, $timeout) = safe_unserialize($_SESSION['login_' . $cookiename]); |
||
| 115 | } |
||
| 116 | else |
||
| 117 | trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR); |
||
| 118 | |||
| 119 | $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); |
||
| 120 | updateMemberData($user_info['id'], array('password_salt' => $user_settings['password_salt'])); |
||
| 121 | |||
| 122 | // Preserve the 2FA cookie? |
||
| 123 | View Code Duplication | if (!empty($modSettings['tfa_mode']) && !empty($_COOKIE[$cookiename . '_tfa'])) |
|
| 124 | { |
||
| 125 | $tfadata = smf_json_decode($_COOKIE[$cookiename . '_tfa'], true); |
||
| 126 | |||
| 127 | // If that didn't work, try unserialize instead... |
||
| 128 | if (is_null($tfadata)) |
||
| 129 | $tfadata = safe_unserialize($_COOKIE[$cookiename . '_tfa']); |
||
| 130 | |||
| 131 | list ($tfamember, $tfasecret, $exp, $state, $preserve) = $tfadata; |
||
| 132 | |||
| 133 | // If we're preserving the cookie, reset it with updated salt |
||
| 134 | if ($preserve && time() < $exp) |
||
| 135 | setTFACookie(3153600, $user_info['password_salt'], hash_salt($user_settings['tfa_backup'], $user_settings['password_salt']), true); |
||
| 136 | else |
||
| 137 | setTFACookie(-3600, 0, ''); |
||
| 138 | } |
||
| 139 | |||
| 140 | setLoginCookie($timeout - time(), $user_info['id'], hash_salt($user_settings['passwd'], $user_settings['password_salt'])); |
||
| 141 | |||
| 142 | redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']); |
||
| 143 | } |
||
| 144 | // Double check the cookie... |
||
| 145 | elseif (isset($_GET['sa']) && $_GET['sa'] == 'check') |
||
| 146 | { |
||
| 147 | // Strike! You're outta there! |
||
| 148 | if ($_GET['member'] != $user_info['id']) |
||
| 149 | fatal_lang_error('login_cookie_error', false); |
||
| 150 | |||
| 151 | $user_info['can_mod'] = allowedTo('access_mod_center') || (!$user_info['is_guest'] && ($user_info['mod_cache']['gq'] != '0=1' || $user_info['mod_cache']['bq'] != '0=1' || ($modSettings['postmod_active'] && !empty($user_info['mod_cache']['ap'])))); |
||
| 152 | |||
| 153 | // Some whitelisting for login_url... |
||
| 154 | if (empty($_SESSION['login_url'])) |
||
| 155 | redirectexit(empty($user_settings['tfa_secret']) ? '' : 'action=logintfa'); |
||
| 156 | elseif (!empty($_SESSION['login_url']) && (strpos($_SESSION['login_url'], 'http://') === false && strpos($_SESSION['login_url'], 'https://') === false)) |
||
| 157 | { |
||
| 158 | unset ($_SESSION['login_url']); |
||
| 159 | redirectexit(empty($user_settings['tfa_secret']) ? '' : 'action=logintfa'); |
||
| 160 | } |
||
| 161 | else |
||
| 162 | { |
||
| 163 | // Best not to clutter the session data too much... |
||
| 164 | $temp = $_SESSION['login_url']; |
||
| 165 | unset($_SESSION['login_url']); |
||
| 166 | |||
| 167 | redirectexit($temp); |
||
| 168 | } |
||
| 169 | } |
||
| 170 | |||
| 171 | // Beyond this point you are assumed to be a guest trying to login. |
||
| 172 | if (!$user_info['is_guest']) |
||
| 173 | redirectexit(); |
||
| 174 | |||
| 175 | // Are you guessing with a script? |
||
| 176 | checkSession(); |
||
| 177 | validateToken('login'); |
||
| 178 | spamProtection('login'); |
||
| 179 | |||
| 180 | // Set the login_url if it's not already set (but careful not to send us to an attachment). |
||
| 181 | if ((empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0) || (isset($_GET['quicklogin']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'login') === false)) |
||
| 182 | $_SESSION['login_url'] = $_SESSION['old_url']; |
||
| 183 | |||
| 184 | // Been guessing a lot, haven't we? |
||
| 185 | if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) |
||
| 186 | fatal_lang_error('login_threshold_fail', 'critical'); |
||
| 187 | |||
| 188 | // Set up the cookie length. (if it's invalid, just fall through and use the default.) |
||
| 189 | if (isset($_POST['cookieneverexp']) || (!empty($_POST['cookielength']) && $_POST['cookielength'] == -1)) |
||
| 190 | $modSettings['cookieTime'] = 3153600; |
||
| 191 | elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 && $_POST['cookielength'] <= 525600)) |
||
| 192 | $modSettings['cookieTime'] = (int) $_POST['cookielength']; |
||
| 193 | |||
| 194 | loadLanguage('Login'); |
||
| 195 | // Load the template stuff. |
||
| 196 | loadTemplate('Login'); |
||
| 197 | $context['sub_template'] = 'login'; |
||
| 198 | |||
| 199 | // Set up the default/fallback stuff. |
||
| 200 | $context['default_username'] = isset($_POST['user']) ? preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', $smcFunc['htmlspecialchars']($_POST['user'])) : ''; |
||
| 201 | $context['default_password'] = ''; |
||
| 202 | $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600; |
||
| 203 | $context['login_errors'] = array($txt['error_occured']); |
||
| 204 | $context['page_title'] = $txt['login']; |
||
| 205 | |||
| 206 | // Add the login chain to the link tree. |
||
| 207 | $context['linktree'][] = array( |
||
| 208 | 'url' => $scripturl . '?action=login', |
||
| 209 | 'name' => $txt['login'], |
||
| 210 | ); |
||
| 211 | |||
| 212 | // You forgot to type your username, dummy! |
||
| 213 | View Code Duplication | if (!isset($_POST['user']) || $_POST['user'] == '') |
|
| 214 | { |
||
| 215 | $context['login_errors'] = array($txt['need_username']); |
||
| 216 | return; |
||
| 217 | } |
||
| 218 | |||
| 219 | // Hmm... maybe 'admin' will login with no password. Uhh... NO! |
||
| 220 | View Code Duplication | if (!isset($_POST['passwrd']) || $_POST['passwrd'] == '') |
|
| 221 | { |
||
| 222 | $context['login_errors'] = array($txt['no_password']); |
||
| 223 | return; |
||
| 224 | } |
||
| 225 | |||
| 226 | // No funky symbols either. |
||
| 227 | if (preg_match('~[<>&"\'=\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0) |
||
| 228 | { |
||
| 229 | $context['login_errors'] = array($txt['error_invalid_characters_username']); |
||
| 230 | return; |
||
| 231 | } |
||
| 232 | |||
| 233 | // And if it's too long, trim it back. |
||
| 234 | if ($smcFunc['strlen']($_POST['user']) > 80) |
||
| 235 | { |
||
| 236 | $_POST['user'] = $smcFunc['substr']($_POST['user'], 0, 79); |
||
| 237 | $context['default_username'] = preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', $smcFunc['htmlspecialchars']($_POST['user'])); |
||
| 238 | } |
||
| 239 | |||
| 240 | |||
| 241 | // Are we using any sort of integration to validate the login? |
||
| 242 | if (in_array('retry', call_integration_hook('integrate_validate_login', array($_POST['user'], isset($_POST['passwrd']) ? $_POST['passwrd'] : null, $modSettings['cookieTime'])), true)) |
||
| 243 | { |
||
| 244 | $context['login_errors'] = array($txt['incorrect_password']); |
||
| 245 | return; |
||
| 246 | } |
||
| 247 | |||
| 248 | // Load the data up! |
||
| 249 | $request = $smcFunc['db_query']('', ' |
||
| 250 | SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, |
||
| 251 | passwd_flood, tfa_secret |
||
| 252 | FROM {db_prefix}members |
||
| 253 | WHERE ' . ($smcFunc['db_case_sensitive'] ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . ' |
||
| 254 | LIMIT 1', |
||
| 255 | array( |
||
| 256 | 'user_name' => $smcFunc['db_case_sensitive'] ? strtolower($_POST['user']) : $_POST['user'], |
||
| 257 | ) |
||
| 258 | ); |
||
| 259 | // Probably mistyped or their email, try it as an email address. (member_name first, though!) |
||
| 260 | if ($smcFunc['db_num_rows']($request) == 0 && strpos($_POST['user'], '@') !== false) |
||
| 261 | { |
||
| 262 | $smcFunc['db_free_result']($request); |
||
| 263 | |||
| 264 | $request = $smcFunc['db_query']('', ' |
||
| 265 | SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, |
||
| 266 | passwd_flood, tfa_secret |
||
| 267 | FROM {db_prefix}members |
||
| 268 | WHERE email_address = {string:user_name} |
||
| 269 | LIMIT 1', |
||
| 270 | array( |
||
| 271 | 'user_name' => $_POST['user'], |
||
| 272 | ) |
||
| 273 | ); |
||
| 274 | } |
||
| 275 | |||
| 276 | // Let them try again, it didn't match anything... |
||
| 277 | if ($smcFunc['db_num_rows']($request) == 0) |
||
| 278 | { |
||
| 279 | $context['login_errors'] = array($txt['username_no_exist']); |
||
| 280 | return; |
||
| 281 | } |
||
| 282 | |||
| 283 | $user_settings = $smcFunc['db_fetch_assoc']($request); |
||
| 284 | $smcFunc['db_free_result']($request); |
||
| 285 | |||
| 286 | // Bad password! Thought you could fool the database?! |
||
| 287 | if (!hash_verify_password($user_settings['member_name'], un_htmlspecialchars($_POST['passwrd']), $user_settings['passwd'])) |
||
| 288 | { |
||
| 289 | // Let's be cautious, no hacking please. thanx. |
||
| 290 | validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); |
||
| 291 | |||
| 292 | // Maybe we were too hasty... let's try some other authentication methods. |
||
| 293 | $other_passwords = array(); |
||
| 294 | |||
| 295 | // None of the below cases will be used most of the time (because the salt is normally set.) |
||
| 296 | if (!empty($modSettings['enable_password_conversion']) && $user_settings['password_salt'] == '') |
||
| 297 | { |
||
| 298 | // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all. |
||
| 299 | $other_passwords[] = crypt($_POST['passwrd'], substr($_POST['passwrd'], 0, 2)); |
||
| 300 | $other_passwords[] = crypt($_POST['passwrd'], substr($user_settings['passwd'], 0, 2)); |
||
| 301 | $other_passwords[] = md5($_POST['passwrd']); |
||
| 302 | $other_passwords[] = sha1($_POST['passwrd']); |
||
| 303 | $other_passwords[] = md5_hmac($_POST['passwrd'], strtolower($user_settings['member_name'])); |
||
| 304 | $other_passwords[] = md5($_POST['passwrd'] . strtolower($user_settings['member_name'])); |
||
| 305 | $other_passwords[] = md5(md5($_POST['passwrd'])); |
||
| 306 | $other_passwords[] = $_POST['passwrd']; |
||
| 307 | |||
| 308 | // This one is a strange one... MyPHP, crypt() on the MD5 hash. |
||
| 309 | $other_passwords[] = crypt(md5($_POST['passwrd']), md5($_POST['passwrd'])); |
||
| 310 | |||
| 311 | // Snitz style - SHA-256. Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway. |
||
| 312 | if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256')) |
||
| 313 | $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_POST['passwrd'])); |
||
| 314 | |||
| 315 | // phpBB3 users new hashing. We now support it as well ;). |
||
| 316 | $other_passwords[] = phpBB3_password_check($_POST['passwrd'], $user_settings['passwd']); |
||
| 317 | |||
| 318 | // APBoard 2 Login Method. |
||
| 319 | $other_passwords[] = md5(crypt($_POST['passwrd'], 'CRYPT_MD5')); |
||
| 320 | } |
||
| 321 | // The hash should be 40 if it's SHA-1, so we're safe with more here too. |
||
| 322 | elseif (!empty($modSettings['enable_password_conversion']) && strlen($user_settings['passwd']) == 32) |
||
| 323 | { |
||
| 324 | // vBulletin 3 style hashing? Let's welcome them with open arms \o/. |
||
| 325 | $other_passwords[] = md5(md5($_POST['passwrd']) . stripslashes($user_settings['password_salt'])); |
||
| 326 | |||
| 327 | // Hmm.. p'raps it's Invision 2 style? |
||
| 328 | $other_passwords[] = md5(md5($user_settings['password_salt']) . md5($_POST['passwrd'])); |
||
| 329 | |||
| 330 | // Some common md5 ones. |
||
| 331 | $other_passwords[] = md5($user_settings['password_salt'] . $_POST['passwrd']); |
||
| 332 | $other_passwords[] = md5($_POST['passwrd'] . $user_settings['password_salt']); |
||
| 333 | } |
||
| 334 | elseif (strlen($user_settings['passwd']) == 40) |
||
| 335 | { |
||
| 336 | // Maybe they are using a hash from before the password fix. |
||
| 337 | // This is also valid for SMF 1.1 to 2.0 style of hashing, changed to bcrypt in SMF 2.1 |
||
| 338 | $other_passwords[] = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); |
||
| 339 | |||
| 340 | // BurningBoard3 style of hashing. |
||
| 341 | if (!empty($modSettings['enable_password_conversion'])) |
||
| 342 | $other_passwords[] = sha1($user_settings['password_salt'] . sha1($user_settings['password_salt'] . sha1($_POST['passwrd']))); |
||
| 343 | |||
| 344 | // Perhaps we converted to UTF-8 and have a valid password being hashed differently. |
||
| 345 | if ($context['character_set'] == 'UTF-8' && !empty($modSettings['previousCharacterSet']) && $modSettings['previousCharacterSet'] != 'utf8') |
||
| 346 | { |
||
| 347 | // Try iconv first, for no particular reason. |
||
| 348 | if (function_exists('iconv')) |
||
| 349 | $other_passwords['iconv'] = sha1(strtolower(iconv('UTF-8', $modSettings['previousCharacterSet'], $user_settings['member_name'])) . un_htmlspecialchars(iconv('UTF-8', $modSettings['previousCharacterSet'], $_POST['passwrd']))); |
||
| 350 | |||
| 351 | // Say it aint so, iconv failed! |
||
| 352 | View Code Duplication | if (empty($other_passwords['iconv']) && function_exists('mb_convert_encoding')) |
|
| 353 | $other_passwords[] = sha1(strtolower(mb_convert_encoding($user_settings['member_name'], 'UTF-8', $modSettings['previousCharacterSet'])) . un_htmlspecialchars(mb_convert_encoding($_POST['passwrd'], 'UTF-8', $modSettings['previousCharacterSet']))); |
||
| 354 | } |
||
| 355 | } |
||
| 356 | |||
| 357 | // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid! |
||
| 358 | if (stripos(PHP_OS, 'win') !== 0 && strlen($user_settings['passwd']) < hash_length()) |
||
| 359 | { |
||
| 360 | require_once($sourcedir . '/Subs-Compat.php'); |
||
| 361 | $other_passwords[] = sha1_smf(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); |
||
| 362 | } |
||
| 363 | |||
| 364 | // Allows mods to easily extend the $other_passwords array |
||
| 365 | call_integration_hook('integrate_other_passwords', array(&$other_passwords)); |
||
| 366 | |||
| 367 | // Whichever encryption it was using, let's make it use SMF's now ;). |
||
| 368 | if (in_array($user_settings['passwd'], $other_passwords)) |
||
| 369 | { |
||
| 370 | $user_settings['passwd'] = hash_password($user_settings['member_name'], un_htmlspecialchars($_POST['passwrd'])); |
||
| 371 | $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); |
||
| 372 | |||
| 373 | // Update the password and set up the hash. |
||
| 374 | updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => '')); |
||
| 375 | } |
||
| 376 | // Okay, they for sure didn't enter the password! |
||
| 377 | else |
||
| 378 | { |
||
| 379 | // They've messed up again - keep a count to see if they need a hand. |
||
| 380 | $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? ($_SESSION['failed_login'] + 1) : 1; |
||
| 381 | |||
| 382 | // Hmm... don't remember it, do you? Here, try the password reminder ;). |
||
| 383 | if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) |
||
| 384 | redirectexit('action=reminder'); |
||
| 385 | // We'll give you another chance... |
||
| 386 | else |
||
| 387 | { |
||
| 388 | // Log an error so we know that it didn't go well in the error log. |
||
| 389 | log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); |
||
| 390 | |||
| 391 | $context['login_errors'] = array($txt['incorrect_password']); |
||
| 392 | return; |
||
| 393 | } |
||
| 394 | } |
||
| 395 | } |
||
| 396 | elseif (!empty($user_settings['passwd_flood'])) |
||
| 397 | { |
||
| 398 | // Let's be sure they weren't a little hacker. |
||
| 399 | validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true); |
||
| 400 | |||
| 401 | // If we got here then we can reset the flood counter. |
||
| 402 | updateMemberData($user_settings['id_member'], array('passwd_flood' => '')); |
||
| 403 | } |
||
| 404 | |||
| 405 | // Correct password, but they've got no salt; fix it! |
||
| 406 | if ($user_settings['password_salt'] == '') |
||
| 407 | { |
||
| 408 | $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); |
||
| 409 | updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt'])); |
||
| 410 | } |
||
| 411 | |||
| 412 | // Check their activation status. |
||
| 413 | if (!checkActivation()) |
||
| 414 | return; |
||
| 415 | |||
| 416 | DoLogin(); |
||
| 417 | } |
||
| 418 | |||
| 869 | ?> |
||
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.