[ Index ]

PHP Cross Reference of WordPress

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


Generated: Tue Sep 21 01:00:05 2021 Cross-referenced by PHPXref 0.7.1