[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 * @since 6.8.0 The hashed password value now uses wp_fast_hash() instead of phpass. 64 * 65 * @param int $user_id User ID. 66 * @param array $args { 67 * Arguments used to create the application password. 68 * 69 * @type string $name The name of the application password. 70 * @type string $app_id A UUID provided by the application to uniquely identify it. 71 * } 72 * @return array|WP_Error { 73 * Application password details, or a WP_Error instance if an error occurs. 74 * 75 * @type string $0 The generated application password in plain text. 76 * @type array $1 { 77 * The details about the created password. 78 * 79 * @type string $uuid The unique identifier for the application password. 80 * @type string $app_id A UUID provided by the application to uniquely identify it. 81 * @type string $name The name of the application password. 82 * @type string $password A one-way hash of the password. 83 * @type int $created Unix timestamp of when the password was created. 84 * @type null $last_used Null. 85 * @type null $last_ip Null. 86 * } 87 * } 88 */ 89 public static function create_new_application_password( $user_id, $args = array() ) { 90 if ( ! empty( $args['name'] ) ) { 91 $args['name'] = sanitize_text_field( $args['name'] ); 92 } 93 94 if ( empty( $args['name'] ) ) { 95 return new WP_Error( 'application_password_empty_name', __( 'An application name is required to create an application password.' ), array( 'status' => 400 ) ); 96 } 97 98 $new_password = wp_generate_password( static::PW_LENGTH, false ); 99 $hashed_password = self::hash_password( $new_password ); 100 101 $new_item = array( 102 'uuid' => wp_generate_uuid4(), 103 'app_id' => empty( $args['app_id'] ) ? '' : $args['app_id'], 104 'name' => $args['name'], 105 'password' => $hashed_password, 106 'created' => time(), 107 'last_used' => null, 108 'last_ip' => null, 109 ); 110 111 $passwords = static::get_user_application_passwords( $user_id ); 112 $passwords[] = $new_item; 113 $saved = static::set_user_application_passwords( $user_id, $passwords ); 114 115 if ( ! $saved ) { 116 return new WP_Error( 'db_error', __( 'Could not save application password.' ) ); 117 } 118 119 $network_id = get_main_network_id(); 120 if ( ! get_network_option( $network_id, self::OPTION_KEY_IN_USE ) ) { 121 update_network_option( $network_id, self::OPTION_KEY_IN_USE, true ); 122 } 123 124 /** 125 * Fires when an application password is created. 126 * 127 * @since 5.6.0 128 * @since 6.8.0 The hashed password value now uses wp_fast_hash() instead of phpass. 129 * 130 * @param int $user_id The user ID. 131 * @param array $new_item { 132 * The details about the created password. 133 * 134 * @type string $uuid The unique identifier for the application password. 135 * @type string $app_id A UUID provided by the application to uniquely identify it. 136 * @type string $name The name of the application password. 137 * @type string $password A one-way hash of the password. 138 * @type int $created Unix timestamp of when the password was created. 139 * @type null $last_used Null. 140 * @type null $last_ip Null. 141 * } 142 * @param string $new_password The generated application password in plain text. 143 * @param array $args { 144 * Arguments used to create the application password. 145 * 146 * @type string $name The name of the application password. 147 * @type string $app_id A UUID provided by the application to uniquely identify it. 148 * } 149 */ 150 do_action( 'wp_create_application_password', $user_id, $new_item, $new_password, $args ); 151 152 return array( $new_password, $new_item ); 153 } 154 155 /** 156 * Gets a user's application passwords. 157 * 158 * @since 5.6.0 159 * 160 * @param int $user_id User ID. 161 * @return array { 162 * The list of application passwords. 163 * 164 * @type array ...$0 { 165 * @type string $uuid The unique identifier for the application password. 166 * @type string $app_id A UUID provided by the application to uniquely identify it. 167 * @type string $name The name of the application password. 168 * @type string $password A one-way hash of the password. 169 * @type int $created Unix timestamp of when the password was created. 170 * @type int|null $last_used The Unix timestamp of the GMT date the application password was last used. 171 * @type string|null $last_ip The IP address the application password was last used by. 172 * } 173 * } 174 */ 175 public static function get_user_application_passwords( $user_id ) { 176 $passwords = get_user_meta( $user_id, static::USERMETA_KEY_APPLICATION_PASSWORDS, true ); 177 178 if ( ! is_array( $passwords ) ) { 179 return array(); 180 } 181 182 $save = false; 183 184 foreach ( $passwords as $i => $password ) { 185 if ( ! isset( $password['uuid'] ) ) { 186 $passwords[ $i ]['uuid'] = wp_generate_uuid4(); 187 $save = true; 188 } 189 } 190 191 if ( $save ) { 192 static::set_user_application_passwords( $user_id, $passwords ); 193 } 194 195 return $passwords; 196 } 197 198 /** 199 * Gets a user's application password with the given UUID. 200 * 201 * @since 5.6.0 202 * 203 * @param int $user_id User ID. 204 * @param string $uuid The password's UUID. 205 * @return array|null { 206 * The application password if found, null otherwise. 207 * 208 * @type string $uuid The unique identifier for the application password. 209 * @type string $app_id A UUID provided by the application to uniquely identify it. 210 * @type string $name The name of the application password. 211 * @type string $password A one-way hash of the password. 212 * @type int $created Unix timestamp of when the password was created. 213 * @type int|null $last_used The Unix timestamp of the GMT date the application password was last used. 214 * @type string|null $last_ip The IP address the application password was last used by. 215 * } 216 */ 217 public static function get_user_application_password( $user_id, $uuid ) { 218 $passwords = static::get_user_application_passwords( $user_id ); 219 220 foreach ( $passwords as $password ) { 221 if ( $password['uuid'] === $uuid ) { 222 return $password; 223 } 224 } 225 226 return null; 227 } 228 229 /** 230 * Checks if an application password with the given name exists for this user. 231 * 232 * @since 5.7.0 233 * 234 * @param int $user_id User ID. 235 * @param string $name Application name. 236 * @return bool Whether the provided application name exists. 237 */ 238 public static function application_name_exists_for_user( $user_id, $name ) { 239 $passwords = static::get_user_application_passwords( $user_id ); 240 241 foreach ( $passwords as $password ) { 242 if ( strtolower( $password['name'] ) === strtolower( $name ) ) { 243 return true; 244 } 245 } 246 247 return false; 248 } 249 250 /** 251 * Updates an application password. 252 * 253 * @since 5.6.0 254 * @since 6.8.0 The actual password should now be hashed using wp_fast_hash(). 255 * 256 * @param int $user_id User ID. 257 * @param string $uuid The password's UUID. 258 * @param array $update { 259 * Information about the application password to update. 260 * 261 * @type string $uuid The unique identifier for the application password. 262 * @type string $app_id A UUID provided by the application to uniquely identify it. 263 * @type string $name The name of the application password. 264 * @type string $password A one-way hash of the password. 265 * @type int $created Unix timestamp of when the password was created. 266 * @type int|null $last_used The Unix timestamp of the GMT date the application password was last used. 267 * @type string|null $last_ip The IP address the application password was last used by. 268 * } 269 * @return true|WP_Error True if successful, otherwise a WP_Error instance is returned on error. 270 */ 271 public static function update_application_password( $user_id, $uuid, $update = array() ) { 272 $passwords = static::get_user_application_passwords( $user_id ); 273 274 foreach ( $passwords as &$item ) { 275 if ( $item['uuid'] !== $uuid ) { 276 continue; 277 } 278 279 if ( ! empty( $update['name'] ) ) { 280 $update['name'] = sanitize_text_field( $update['name'] ); 281 } 282 283 $save = false; 284 285 if ( ! empty( $update['name'] ) && $item['name'] !== $update['name'] ) { 286 $item['name'] = $update['name']; 287 $save = true; 288 } 289 290 if ( $save ) { 291 $saved = static::set_user_application_passwords( $user_id, $passwords ); 292 293 if ( ! $saved ) { 294 return new WP_Error( 'db_error', __( 'Could not save application password.' ) ); 295 } 296 } 297 298 /** 299 * Fires when an application password is updated. 300 * 301 * @since 5.6.0 302 * @since 6.8.0 The password is now hashed using wp_fast_hash() instead of phpass. 303 * Existing passwords may still be hashed using phpass. 304 * 305 * @param int $user_id The user ID. 306 * @param array $item { 307 * The updated application password details. 308 * 309 * @type string $uuid The unique identifier for the application password. 310 * @type string $app_id A UUID provided by the application to uniquely identify it. 311 * @type string $name The name of the application password. 312 * @type string $password A one-way hash of the password. 313 * @type int $created Unix timestamp of when the password was created. 314 * @type int|null $last_used The Unix timestamp of the GMT date the application password was last used. 315 * @type string|null $last_ip The IP address the application password was last used by. 316 * } 317 * @param array $update The information to update. 318 */ 319 do_action( 'wp_update_application_password', $user_id, $item, $update ); 320 321 return true; 322 } 323 324 return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) ); 325 } 326 327 /** 328 * Records that an application password has been used. 329 * 330 * @since 5.6.0 331 * 332 * @param int $user_id User ID. 333 * @param string $uuid The password's UUID. 334 * @return true|WP_Error True if the usage was recorded, a WP_Error if an error occurs. 335 */ 336 public static function record_application_password_usage( $user_id, $uuid ) { 337 $passwords = static::get_user_application_passwords( $user_id ); 338 339 foreach ( $passwords as &$password ) { 340 if ( $password['uuid'] !== $uuid ) { 341 continue; 342 } 343 344 // Only record activity once a day. 345 if ( $password['last_used'] + DAY_IN_SECONDS > time() ) { 346 return true; 347 } 348 349 $password['last_used'] = time(); 350 $password['last_ip'] = $_SERVER['REMOTE_ADDR']; 351 352 $saved = static::set_user_application_passwords( $user_id, $passwords ); 353 354 if ( ! $saved ) { 355 return new WP_Error( 'db_error', __( 'Could not save application password.' ) ); 356 } 357 358 return true; 359 } 360 361 // Specified application password not found! 362 return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) ); 363 } 364 365 /** 366 * Deletes an application password. 367 * 368 * @since 5.6.0 369 * 370 * @param int $user_id User ID. 371 * @param string $uuid The password's UUID. 372 * @return true|WP_Error Whether the password was successfully found and deleted, a WP_Error otherwise. 373 */ 374 public static function delete_application_password( $user_id, $uuid ) { 375 $passwords = static::get_user_application_passwords( $user_id ); 376 377 foreach ( $passwords as $key => $item ) { 378 if ( $item['uuid'] === $uuid ) { 379 unset( $passwords[ $key ] ); 380 $saved = static::set_user_application_passwords( $user_id, $passwords ); 381 382 if ( ! $saved ) { 383 return new WP_Error( 'db_error', __( 'Could not delete application password.' ) ); 384 } 385 386 /** 387 * Fires when an application password is deleted. 388 * 389 * @since 5.6.0 390 * 391 * @param int $user_id The user ID. 392 * @param array $item The data about the application password. 393 */ 394 do_action( 'wp_delete_application_password', $user_id, $item ); 395 396 return true; 397 } 398 } 399 400 return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) ); 401 } 402 403 /** 404 * Deletes all application passwords for the given user. 405 * 406 * @since 5.6.0 407 * 408 * @param int $user_id User ID. 409 * @return int|WP_Error The number of passwords that were deleted or a WP_Error on failure. 410 */ 411 public static function delete_all_application_passwords( $user_id ) { 412 $passwords = static::get_user_application_passwords( $user_id ); 413 414 if ( $passwords ) { 415 $saved = static::set_user_application_passwords( $user_id, array() ); 416 417 if ( ! $saved ) { 418 return new WP_Error( 'db_error', __( 'Could not delete application passwords.' ) ); 419 } 420 421 foreach ( $passwords as $item ) { 422 /** This action is documented in wp-includes/class-wp-application-passwords.php */ 423 do_action( 'wp_delete_application_password', $user_id, $item ); 424 } 425 426 return count( $passwords ); 427 } 428 429 return 0; 430 } 431 432 /** 433 * Sets a user's application passwords. 434 * 435 * @since 5.6.0 436 * 437 * @param int $user_id User ID. 438 * @param array $passwords { 439 * The list of application passwords. 440 * 441 * @type array ...$0 { 442 * @type string $uuid The unique identifier for the application password. 443 * @type string $app_id A UUID provided by the application to uniquely identify it. 444 * @type string $name The name of the application password. 445 * @type string $password A one-way hash of the password. 446 * @type int $created Unix timestamp of when the password was created. 447 * @type int|null $last_used The Unix timestamp of the GMT date the application password was last used. 448 * @type string|null $last_ip The IP address the application password was last used by. 449 * } 450 * } 451 * @return int|bool User meta ID if the key didn't exist (ie. this is the first time that an application password 452 * has been saved for the user), true on successful update, false on failure or if the value passed 453 * is the same as the one that is already in the database. 454 */ 455 protected static function set_user_application_passwords( $user_id, $passwords ) { 456 return update_user_meta( $user_id, static::USERMETA_KEY_APPLICATION_PASSWORDS, $passwords ); 457 } 458 459 /** 460 * Sanitizes and then splits a password into smaller chunks. 461 * 462 * @since 5.6.0 463 * 464 * @param string $raw_password The raw application password. 465 * @return string The chunked password. 466 */ 467 public static function chunk_password( 468 #[\SensitiveParameter] 469 $raw_password 470 ) { 471 $raw_password = preg_replace( '/[^a-z\d]/i', '', $raw_password ); 472 473 return trim( chunk_split( $raw_password, 4, ' ' ) ); 474 } 475 476 /** 477 * Hashes a plaintext application password. 478 * 479 * @since 6.8.0 480 * 481 * @param string $password Plaintext password. 482 * @return string Hashed password. 483 */ 484 public static function hash_password( 485 #[\SensitiveParameter] 486 string $password 487 ): string { 488 return wp_fast_hash( $password ); 489 } 490 491 /** 492 * Checks a plaintext application password against a hashed password. 493 * 494 * @since 6.8.0 495 * 496 * @param string $password Plaintext password. 497 * @param string $hash Hash of the password to check against. 498 * @return bool Whether the password matches the hashed password. 499 */ 500 public static function check_password( 501 #[\SensitiveParameter] 502 string $password, 503 string $hash 504 ): bool { 505 return wp_verify_fast_hash( $password, $hash ); 506 } 507 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Feb 22 08:20:01 2025 | Cross-referenced by PHPXref |