[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-application-passwords.php (source)

   1  <?php
   2  /**
   3   * WP_Application_Passwords class
   4   *
   5   * @package WordPress
   6   * @since   5.6.0
   7   */
   8  
   9  /**
  10   * Class for displaying, modifying, and sanitizing application passwords.
  11   *
  12   * @package WordPress
  13   */
  14  #[AllowDynamicProperties]
  15  class WP_Application_Passwords {
  16  
  17      /**
  18       * The application passwords user meta key.
  19       *
  20       * @since 5.6.0
  21       *
  22       * @var string
  23       */
  24      const USERMETA_KEY_APPLICATION_PASSWORDS = '_application_passwords';
  25  
  26      /**
  27       * The option name used to store whether application passwords are in use.
  28       *
  29       * @since 5.6.0
  30       *
  31       * @var string
  32       */
  33      const OPTION_KEY_IN_USE = 'using_application_passwords';
  34  
  35      /**
  36       * The generated application password length.
  37       *
  38       * @since 5.6.0
  39       *
  40       * @var int
  41       */
  42      const PW_LENGTH = 24;
  43  
  44      /**
  45       * Checks if application passwords are being used by the site.
  46       *
  47       * This returns true if at least one application password has ever been created.
  48       *
  49       * @since 5.6.0
  50       *
  51       * @return bool
  52       */
  53  	public static function is_in_use() {
  54          $network_id = get_main_network_id();
  55          return (bool) get_network_option( $network_id, self::OPTION_KEY_IN_USE );
  56      }
  57  
  58      /**
  59       * Creates a new application password.
  60       *
  61       * @since 5.6.0
  62       * @since 5.7.0 Returns WP_Error if application name already exists.
  63       *
  64       * @param int   $user_id  User ID.
  65       * @param array $args     {
  66       *     Arguments used to create the application password.
  67       *
  68       *     @type string $name   The name of the application password.
  69       *     @type string $app_id A UUID provided by the application to uniquely identify it.
  70       * }
  71       * @return array|WP_Error {
  72       *     Application password details, or a WP_Error instance if an error occurs.
  73       *
  74       *     @type string $0 The generated application password in plain text.
  75       *     @type array  $1 {
  76       *         The details about the created password.
  77       *
  78       *         @type string $uuid      The unique identifier for the application password.
  79       *         @type string $app_id    A UUID provided by the application to uniquely identify it.
  80       *         @type string $name      The name of the application password.
  81       *         @type string $password  A one-way hash of the password.
  82       *         @type int    $created   Unix timestamp of when the password was created.
  83       *         @type null   $last_used Null.
  84       *         @type null   $last_ip   Null.
  85       *     }
  86       * }
  87       */
  88  	public static function create_new_application_password( $user_id, $args = array() ) {
  89          if ( ! empty( $args['name'] ) ) {
  90              $args['name'] = sanitize_text_field( $args['name'] );
  91          }
  92  
  93          if ( empty( $args['name'] ) ) {
  94              return new WP_Error( 'application_password_empty_name', __( 'An application name is required to create an application password.' ), array( 'status' => 400 ) );
  95          }
  96  
  97          $new_password    = wp_generate_password( static::PW_LENGTH, false );
  98          $hashed_password = wp_hash_password( $new_password );
  99  
 100          $new_item = array(
 101              'uuid'      => wp_generate_uuid4(),
 102              'app_id'    => empty( $args['app_id'] ) ? '' : $args['app_id'],
 103              'name'      => $args['name'],
 104              'password'  => $hashed_password,
 105              'created'   => time(),
 106              'last_used' => null,
 107              'last_ip'   => null,
 108          );
 109  
 110          $passwords   = static::get_user_application_passwords( $user_id );
 111          $passwords[] = $new_item;
 112          $saved       = static::set_user_application_passwords( $user_id, $passwords );
 113  
 114          if ( ! $saved ) {
 115              return new WP_Error( 'db_error', __( 'Could not save application password.' ) );
 116          }
 117  
 118          $network_id = get_main_network_id();
 119          if ( ! get_network_option( $network_id, self::OPTION_KEY_IN_USE ) ) {
 120              update_network_option( $network_id, self::OPTION_KEY_IN_USE, true );
 121          }
 122  
 123          /**
 124           * Fires when an application password is created.
 125           *
 126           * @since 5.6.0
 127           *
 128           * @param int    $user_id      The user ID.
 129           * @param array  $new_item     {
 130           *     The details about the created password.
 131           *
 132           *     @type string $uuid      The unique identifier for the application password.
 133           *     @type string $app_id    A UUID provided by the application to uniquely identify it.
 134           *     @type string $name      The name of the application password.
 135           *     @type string $password  A one-way hash of the password.
 136           *     @type int    $created   Unix timestamp of when the password was created.
 137           *     @type null   $last_used Null.
 138           *     @type null   $last_ip   Null.
 139           * }
 140           * @param string $new_password The generated application password in plain text.
 141           * @param array  $args         {
 142           *     Arguments used to create the application password.
 143           *
 144           *     @type string $name   The name of the application password.
 145           *     @type string $app_id A UUID provided by the application to uniquely identify it.
 146           * }
 147           */
 148          do_action( 'wp_create_application_password', $user_id, $new_item, $new_password, $args );
 149  
 150          return array( $new_password, $new_item );
 151      }
 152  
 153      /**
 154       * Gets a user's application passwords.
 155       *
 156       * @since 5.6.0
 157       *
 158       * @param int $user_id User ID.
 159       * @return array {
 160       *     The list of application passwords.
 161       *
 162       *     @type array ...$0 {
 163       *         @type string      $uuid      The unique identifier for the application password.
 164       *         @type string      $app_id    A UUID provided by the application to uniquely identify it.
 165       *         @type string      $name      The name of the application password.
 166       *         @type string      $password  A one-way hash of the password.
 167       *         @type int         $created   Unix timestamp of when the password was created.
 168       *         @type int|null    $last_used The Unix timestamp of the GMT date the application password was last used.
 169       *         @type string|null $last_ip   The IP address the application password was last used by.
 170       *     }
 171       * }
 172       */
 173  	public static function get_user_application_passwords( $user_id ) {
 174          $passwords = get_user_meta( $user_id, static::USERMETA_KEY_APPLICATION_PASSWORDS, true );
 175  
 176          if ( ! is_array( $passwords ) ) {
 177              return array();
 178          }
 179  
 180          $save = false;
 181  
 182          foreach ( $passwords as $i => $password ) {
 183              if ( ! isset( $password['uuid'] ) ) {
 184                  $passwords[ $i ]['uuid'] = wp_generate_uuid4();
 185                  $save                    = true;
 186              }
 187          }
 188  
 189          if ( $save ) {
 190              static::set_user_application_passwords( $user_id, $passwords );
 191          }
 192  
 193          return $passwords;
 194      }
 195  
 196      /**
 197       * Gets a user's application password with the given UUID.
 198       *
 199       * @since 5.6.0
 200       *
 201       * @param int    $user_id User ID.
 202       * @param string $uuid    The password's UUID.
 203       * @return array|null {
 204       *     The application password if found, null otherwise.
 205       *
 206       *     @type string      $uuid      The unique identifier for the application password.
 207       *     @type string      $app_id    A UUID provided by the application to uniquely identify it.
 208       *     @type string      $name      The name of the application password.
 209       *     @type string      $password  A one-way hash of the password.
 210       *     @type int         $created   Unix timestamp of when the password was created.
 211       *     @type int|null    $last_used The Unix timestamp of the GMT date the application password was last used.
 212       *     @type string|null $last_ip   The IP address the application password was last used by.
 213       * }
 214       */
 215  	public static function get_user_application_password( $user_id, $uuid ) {
 216          $passwords = static::get_user_application_passwords( $user_id );
 217  
 218          foreach ( $passwords as $password ) {
 219              if ( $password['uuid'] === $uuid ) {
 220                  return $password;
 221              }
 222          }
 223  
 224          return null;
 225      }
 226  
 227      /**
 228       * Checks if an application password with the given name exists for this user.
 229       *
 230       * @since 5.7.0
 231       *
 232       * @param int    $user_id User ID.
 233       * @param string $name    Application name.
 234       * @return bool Whether the provided application name exists.
 235       */
 236  	public static function application_name_exists_for_user( $user_id, $name ) {
 237          $passwords = static::get_user_application_passwords( $user_id );
 238  
 239          foreach ( $passwords as $password ) {
 240              if ( strtolower( $password['name'] ) === strtolower( $name ) ) {
 241                  return true;
 242              }
 243          }
 244  
 245          return false;
 246      }
 247  
 248      /**
 249       * Updates an application password.
 250       *
 251       * @since 5.6.0
 252       *
 253       * @param int    $user_id User ID.
 254       * @param string $uuid    The password's UUID.
 255       * @param array  $update  {
 256       *     Information about the application password to update.
 257       *
 258       *     @type string      $uuid      The unique identifier for the application password.
 259       *     @type string      $app_id    A UUID provided by the application to uniquely identify it.
 260       *     @type string      $name      The name of the application password.
 261       *     @type string      $password  A one-way hash of the password.
 262       *     @type int         $created   Unix timestamp of when the password was created.
 263       *     @type int|null    $last_used The Unix timestamp of the GMT date the application password was last used.
 264       *     @type string|null $last_ip   The IP address the application password was last used by.
 265       * }
 266       * @return true|WP_Error True if successful, otherwise a WP_Error instance is returned on error.
 267       */
 268  	public static function update_application_password( $user_id, $uuid, $update = array() ) {
 269          $passwords = static::get_user_application_passwords( $user_id );
 270  
 271          foreach ( $passwords as &$item ) {
 272              if ( $item['uuid'] !== $uuid ) {
 273                  continue;
 274              }
 275  
 276              if ( ! empty( $update['name'] ) ) {
 277                  $update['name'] = sanitize_text_field( $update['name'] );
 278              }
 279  
 280              $save = false;
 281  
 282              if ( ! empty( $update['name'] ) && $item['name'] !== $update['name'] ) {
 283                  $item['name'] = $update['name'];
 284                  $save         = true;
 285              }
 286  
 287              if ( $save ) {
 288                  $saved = static::set_user_application_passwords( $user_id, $passwords );
 289  
 290                  if ( ! $saved ) {
 291                      return new WP_Error( 'db_error', __( 'Could not save application password.' ) );
 292                  }
 293              }
 294  
 295              /**
 296               * Fires when an application password is updated.
 297               *
 298               * @since 5.6.0
 299               *
 300               * @param int   $user_id The user ID.
 301               * @param array $item    {
 302               *     The updated application password details.
 303               *
 304               *     @type string      $uuid      The unique identifier for the application password.
 305               *     @type string      $app_id    A UUID provided by the application to uniquely identify it.
 306               *     @type string      $name      The name of the application password.
 307               *     @type string      $password  A one-way hash of the password.
 308               *     @type int         $created   Unix timestamp of when the password was created.
 309               *     @type int|null    $last_used The Unix timestamp of the GMT date the application password was last used.
 310               *     @type string|null $last_ip   The IP address the application password was last used by.
 311               * }
 312               * @param array $update  The information to update.
 313               */
 314              do_action( 'wp_update_application_password', $user_id, $item, $update );
 315  
 316              return true;
 317          }
 318  
 319          return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) );
 320      }
 321  
 322      /**
 323       * Records that an application password has been used.
 324       *
 325       * @since 5.6.0
 326       *
 327       * @param int    $user_id User ID.
 328       * @param string $uuid    The password's UUID.
 329       * @return true|WP_Error True if the usage was recorded, a WP_Error if an error occurs.
 330       */
 331  	public static function record_application_password_usage( $user_id, $uuid ) {
 332          $passwords = static::get_user_application_passwords( $user_id );
 333  
 334          foreach ( $passwords as &$password ) {
 335              if ( $password['uuid'] !== $uuid ) {
 336                  continue;
 337              }
 338  
 339              // Only record activity once a day.
 340              if ( $password['last_used'] + DAY_IN_SECONDS > time() ) {
 341                  return true;
 342              }
 343  
 344              $password['last_used'] = time();
 345              $password['last_ip']   = $_SERVER['REMOTE_ADDR'];
 346  
 347              $saved = static::set_user_application_passwords( $user_id, $passwords );
 348  
 349              if ( ! $saved ) {
 350                  return new WP_Error( 'db_error', __( 'Could not save application password.' ) );
 351              }
 352  
 353              return true;
 354          }
 355  
 356          // Specified application password not found!
 357          return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) );
 358      }
 359  
 360      /**
 361       * Deletes an application password.
 362       *
 363       * @since 5.6.0
 364       *
 365       * @param int    $user_id User ID.
 366       * @param string $uuid    The password's UUID.
 367       * @return true|WP_Error Whether the password was successfully found and deleted, a WP_Error otherwise.
 368       */
 369  	public static function delete_application_password( $user_id, $uuid ) {
 370          $passwords = static::get_user_application_passwords( $user_id );
 371  
 372          foreach ( $passwords as $key => $item ) {
 373              if ( $item['uuid'] === $uuid ) {
 374                  unset( $passwords[ $key ] );
 375                  $saved = static::set_user_application_passwords( $user_id, $passwords );
 376  
 377                  if ( ! $saved ) {
 378                      return new WP_Error( 'db_error', __( 'Could not delete application password.' ) );
 379                  }
 380  
 381                  /**
 382                   * Fires when an application password is deleted.
 383                   *
 384                   * @since 5.6.0
 385                   *
 386                   * @param int   $user_id The user ID.
 387                   * @param array $item    The data about the application password.
 388                   */
 389                  do_action( 'wp_delete_application_password', $user_id, $item );
 390  
 391                  return true;
 392              }
 393          }
 394  
 395          return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) );
 396      }
 397  
 398      /**
 399       * Deletes all application passwords for the given user.
 400       *
 401       * @since 5.6.0
 402       *
 403       * @param int $user_id User ID.
 404       * @return int|WP_Error The number of passwords that were deleted or a WP_Error on failure.
 405       */
 406  	public static function delete_all_application_passwords( $user_id ) {
 407          $passwords = static::get_user_application_passwords( $user_id );
 408  
 409          if ( $passwords ) {
 410              $saved = static::set_user_application_passwords( $user_id, array() );
 411  
 412              if ( ! $saved ) {
 413                  return new WP_Error( 'db_error', __( 'Could not delete application passwords.' ) );
 414              }
 415  
 416              foreach ( $passwords as $item ) {
 417                  /** This action is documented in wp-includes/class-wp-application-passwords.php */
 418                  do_action( 'wp_delete_application_password', $user_id, $item );
 419              }
 420  
 421              return count( $passwords );
 422          }
 423  
 424          return 0;
 425      }
 426  
 427      /**
 428       * Sets a user's application passwords.
 429       *
 430       * @since 5.6.0
 431       *
 432       * @param int   $user_id   User ID.
 433       * @param array $passwords {
 434       *     The list of application passwords.
 435       *
 436       *     @type array ...$0 {
 437       *         @type string      $uuid      The unique identifier for the application password.
 438       *         @type string      $app_id    A UUID provided by the application to uniquely identify it.
 439       *         @type string      $name      The name of the application password.
 440       *         @type string      $password  A one-way hash of the password.
 441       *         @type int         $created   Unix timestamp of when the password was created.
 442       *         @type int|null    $last_used The Unix timestamp of the GMT date the application password was last used.
 443       *         @type string|null $last_ip   The IP address the application password was last used by.
 444       *     }
 445       * }
 446       * @return int|bool User meta ID if the key didn't exist (ie. this is the first time that an application password
 447       *                  has been saved for the user), true on successful update, false on failure or if the value passed
 448       *                  is the same as the one that is already in the database.
 449       */
 450  	protected static function set_user_application_passwords( $user_id, $passwords ) {
 451          return update_user_meta( $user_id, static::USERMETA_KEY_APPLICATION_PASSWORDS, $passwords );
 452      }
 453  
 454      /**
 455       * Sanitizes and then splits a password into smaller chunks.
 456       *
 457       * @since 5.6.0
 458       *
 459       * @param string $raw_password The raw application password.
 460       * @return string The chunked password.
 461       */
 462  	public static function chunk_password( $raw_password ) {
 463          $raw_password = preg_replace( '/[^a-z\d]/i', '', $raw_password );
 464  
 465          return trim( chunk_split( $raw_password, 4, ' ' ) );
 466      }
 467  }


Generated : Thu Nov 21 08:20:01 2024 Cross-referenced by PHPXref