Textpattern | PHP Cross Reference | Content Management Systems |
Description: Collection of password handling functions.
1 <?php 2 3 /* 4 * Textpattern Content Management System 5 * http://textpattern.com 6 * 7 * Copyright (C) 2016 The Textpattern Development Team 8 * 9 * This file is part of Textpattern. 10 * 11 * Textpattern is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation, version 2. 14 * 15 * Textpattern is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with Textpattern. If not, see <http://www.gnu.org/licenses/>. 22 */ 23 24 /** 25 * Collection of password handling functions. 26 * 27 * @package User 28 */ 29 30 /** 31 * Emails a new user with account details and requests they set a password. 32 * 33 * @param string $name The login name 34 * @return bool FALSE on error. 35 */ 36 37 function send_account_activation($name) 38 { 39 global $sitename; 40 41 require_privs('admin.edit'); 42 43 $rs = safe_row("user_id, email, nonce, RealName, pass", 'txp_users', "name = '".doSlash($name)."'"); 44 45 if ($rs) { 46 extract($rs); 47 48 $expiryTimestamp = time() + (60 * 60 * ACTIVATION_EXPIRY_HOURS); 49 50 $activation_code = generate_user_token($user_id, 'account_activation', $expiryTimestamp, $pass, $nonce); 51 52 $expiryYear = safe_strftime('%Y', $expiryTimestamp); 53 $expiryMonth = safe_strftime('%B', $expiryTimestamp); 54 $expiryDay = safe_strftime('%Oe', $expiryTimestamp); 55 $expiryTime = safe_strftime('%H:%M %Z', $expiryTimestamp); 56 57 $message = gTxt('salutation', array('{name}' => $RealName)). 58 n.n.gTxt('you_have_been_registered').' '.$sitename. 59 60 n.n.gTxt('your_login_is').': '.$name. 61 n.n.gTxt('account_activation_confirmation'). 62 n.hu.'textpattern/index.php?activate='.$activation_code. 63 n.n.gTxt('link_expires', array( 64 '{year}' => $expiryYear, 65 '{month}' => $expiryMonth, 66 '{day}' => $expiryDay, 67 '{time}' => $expiryTime, 68 )); 69 70 if (txpMail($email, "[$sitename] ".gTxt('account_activation'), $message)) { 71 return gTxt('login_sent_to', array('{email}' => $email)); 72 } else { 73 return array(gTxt('could_not_mail'), E_ERROR); 74 } 75 } 76 } 77 78 /** 79 * Sends a password reset link to a user's email address. 80 * 81 * This function will return a success message even when the specified user 82 * doesn't exist. Though an error message could be thrown when a user isn't 83 * found, security best practice prevents leaking existing account names. 84 * 85 * @param string $name The login name 86 * @return string A localized message string 87 * @see send_new_password() 88 * @see reset_author_pass() 89 * @example 90 * echo send_reset_confirmation_request('username'); 91 */ 92 93 function send_reset_confirmation_request($name) 94 { 95 global $sitename; 96 97 $expiryTimestamp = time() + (60 * RESET_EXPIRY_MINUTES); 98 99 $rs = safe_query( 100 "SELECT 101 txp_users.user_id, txp_users.email, 102 txp_users.nonce, txp_users.pass, 103 txp_token.expires 104 FROM ".safe_pfx('txp_users')." txp_users 105 LEFT JOIN ".safe_pfx('txp_token')." txp_token 106 ON txp_users.user_id = txp_token.reference_id 107 AND txp_token.type = 'password_reset' 108 WHERE txp_users.name = '".doSlash($name)."'"); 109 110 $row = nextRow($rs); 111 112 if ($row) { 113 extract($row); 114 115 // Rate limit the reset requests. 116 if ($expires) { 117 $originalExpiry = strtotime($expires); 118 119 if (($expiryTimestamp - $originalExpiry) < (60 * RESET_RATE_LIMIT_MINUTES)) { 120 return gTxt('password_reset_confirmation_request_sent'); 121 } 122 } 123 124 $confirm = generate_user_token($user_id, 'password_reset', $expiryTimestamp, $pass, $nonce); 125 126 $expiryYear = safe_strftime('%Y', $expiryTimestamp); 127 $expiryMonth = safe_strftime('%B', $expiryTimestamp); 128 $expiryDay = safe_strftime('%Oe', $expiryTimestamp); 129 $expiryTime = safe_strftime('%H:%M %Z', $expiryTimestamp); 130 131 $message = gTxt('salutation', array('{name}' => $name)). 132 n.n.gTxt('password_reset_confirmation'). 133 n.hu.'textpattern/index.php?confirm='.$confirm. 134 n.n.gTxt('link_expires', array( 135 '{year}' => $expiryYear, 136 '{month}' => $expiryMonth, 137 '{day}' => $expiryDay, 138 '{time}' => $expiryTime, 139 )); 140 if (txpMail($email, "[$sitename] ".gTxt('password_reset_confirmation_request'), $message)) { 141 return gTxt('password_reset_confirmation_request_sent'); 142 } else { 143 return array(gTxt('could_not_mail'), E_ERROR); 144 } 145 } else { 146 // Though 'unknown_author' could be thrown, send generic 'request_sent' 147 // message instead so that (non-)existence of account names are not leaked. 148 // Since this is a short circuit, there's a possibility of a timing attack 149 // revealing the existence of an account, which we could defend against 150 // to some degree. 151 return gTxt('password_reset_confirmation_request_sent'); 152 } 153 } 154 155 /** 156 * Emails a new user with login details. 157 * 158 * This function can be only executed when the currently authenticated user 159 * trying to send the email was granted 'admin.edit' privileges. 160 * 161 * Should NEVER be used as sending plaintext passwords is wrong. 162 * Will be removed in future, in lieu of sending reset request tokens. 163 * 164 * @param string $RealName The real name 165 * @param string $name The login name 166 * @param string $email The email address 167 * @param string $password The password 168 * @return bool FALSE on error. 169 * @deprecated in 4.6.0 170 * @see send_new_password(), send_reset_confirmation_request 171 * @example 172 * if (send_password('John Doe', 'login', 'example@example.tld', 'password')) 173 * { 174 * echo "Login details sent."; 175 * } 176 */ 177 178 function send_password($RealName, $name, $email, $password) 179 { 180 global $sitename; 181 182 require_privs('admin.edit'); 183 184 $message = gTxt('salutation', array('{name}' => $RealName)). 185 186 n.n.gTxt('you_have_been_registered').' '.$sitename. 187 188 n.n.gTxt('your_login_is').': '.$name. 189 n.gTxt('your_password_is').': '.$password. 190 191 n.n.gTxt('log_in_at').': '.hu.'textpattern/index.php'; 192 193 return txpMail($email, "[$sitename] ".gTxt('your_login_info'), $message); 194 } 195 196 /** 197 * Sends a new password to an existing user. 198 * 199 * If the $name is FALSE, the password is sent to the currently 200 * authenticated user. 201 * 202 * Should NEVER be used as sending plaintext passwords is wrong. 203 * Will be removed in future, in lieu of sending reset request tokens. 204 * 205 * @param string $password The new password 206 * @param string $email The email address 207 * @param string $name The login name 208 * @return bool FALSE on error. 209 * @deprecated in 4.6.0 210 * @see send_reset_confirmation_request 211 * @see reset_author_pass() 212 * @example 213 * $pass = generate_password(); 214 * if (send_new_password($pass, 'example@example.tld', 'user')) 215 * { 216 * echo "Password was sent to 'user'."; 217 * } 218 */ 219 220 function send_new_password($password, $email, $name) 221 { 222 global $txp_user, $sitename; 223 224 if (empty($name)) { 225 $name = $txp_user; 226 } 227 228 $message = gTxt('salutation', array('{name}' => $name)). 229 230 n.n.gTxt('your_password_is').': '.$password. 231 232 n.n.gTxt('log_in_at').': '.hu.'textpattern/index.php'; 233 234 return txpMail($email, "[$sitename] ".gTxt('your_new_password'), $message); 235 } 236 237 /** 238 * Generates a password. 239 * 240 * Generates a random password of given length using the symbols set in 241 * PASSWORD_SYMBOLS constant. 242 * 243 * Should NEVER be used as it is not cryptographically secure. 244 * Will be removed in future, in lieu of sending reset request tokens. 245 * 246 * @param int $length The length of the password 247 * @return string Random plain-text password 248 * @deprecated in 4.6.0 249 * @see \Textpattern\Password\Generate 250 * @see \Textpattern\Password\Random 251 * @example 252 * echo generate_password(128); 253 */ 254 255 function generate_password($length = 10) 256 { 257 static $chars; 258 259 if (!$chars) { 260 $chars = str_split(PASSWORD_SYMBOLS); 261 } 262 263 $pool = false; 264 $pass = ''; 265 266 for ($i = 0; $i < $length; $i++) { 267 if (!$pool) { 268 $pool = $chars; 269 } 270 271 $index = mt_rand(0, count($pool) - 1); 272 $pass .= $pool[$index]; 273 unset($pool[$index]); 274 $pool = array_values($pool); 275 } 276 277 return $pass; 278 } 279 280 /** 281 * Resets the given user's password and emails it. 282 * 283 * The old password is replaced with a new random-generated one. 284 * 285 * Should NEVER be used as sending plaintext passwords is wrong. 286 * Will be removed in future, in lieu of sending reset request tokens. 287 * 288 * @param string $name The login name 289 * @return string A localized message string 290 * @deprecated in 4.6.0 291 * @see PASSWORD_LENGTH 292 * @see generate_password() 293 * @example 294 * echo reset_author_pass('username'); 295 */ 296 297 function reset_author_pass($name) 298 { 299 $email = safe_field("email", 'txp_users', "name = '".doSlash($name)."'"); 300 301 $new_pass = Txp::get('\Textpattern\Password\Random')->generate(PASSWORD_LENGTH); 302 303 $rs = change_user_password($name, $new_pass); 304 305 if ($rs) { 306 if (send_new_password($new_pass, $email, $name)) { 307 return gTxt('password_sent_to').' '.$email; 308 } else { 309 return gTxt('could_not_mail').' '.$email; 310 } 311 } else { 312 return gTxt('could_not_update_author').' '.txpspecialchars($name); 313 } 314 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title