Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/lib/txplib_admin.php - 314 lines - 9816 bytes - Summary - Text - Print

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

title

Description

title

Description

title

title

Body