[ Index ] |
PHP Cross Reference of WordPress |
[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 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 Application 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 { 65 * Arguments used to create the application password. 66 * 67 * @type string $name The name of the application password. 68 * @type string $app_id A UUID provided by the application to uniquely identify it. 69 * } 70 * @return array|WP_Error The first key in the array is the new password, the second is its detailed information. 71 * A WP_Error instance is returned on error. 72 */ 73 public static function create_new_application_password( $user_id, $args = array() ) { 74 if ( ! empty( $args['name'] ) ) { 75 $args['name'] = sanitize_text_field( $args['name'] ); 76 } 77 78 if ( empty( $args['name'] ) ) { 79 return new WP_Error( 'application_password_empty_name', __( 'An application name is required to create an application password.' ), array( 'status' => 400 ) ); 80 } 81 82 if ( self::application_name_exists_for_user( $user_id, $args['name'] ) ) { 83 return new WP_Error( 'application_password_duplicate_name', __( 'Each application name should be unique.' ), array( 'status' => 409 ) ); 84 } 85 86 $new_password = wp_generate_password( static::PW_LENGTH, false ); 87 $hashed_password = wp_hash_password( $new_password ); 88 89 $new_item = array( 90 'uuid' => wp_generate_uuid4(), 91 'app_id' => empty( $args['app_id'] ) ? '' : $args['app_id'], 92 'name' => $args['name'], 93 'password' => $hashed_password, 94 'created' => time(), 95 'last_used' => null, 96 'last_ip' => null, 97 ); 98 99 $passwords = static::get_user_application_passwords( $user_id ); 100 $passwords[] = $new_item; 101 $saved = static::set_user_application_passwords( $user_id, $passwords ); 102 103 if ( ! $saved ) { 104 return new WP_Error( 'db_error', __( 'Could not save application password.' ) ); 105 } 106 107 $network_id = get_main_network_id(); 108 if ( ! get_network_option( $network_id, self::OPTION_KEY_IN_USE ) ) { 109 update_network_option( $network_id, self::OPTION_KEY_IN_USE, true ); 110 } 111 112 /** 113 * Fires when an application password is created. 114 * 115 * @since 5.6.0 116 * 117 * @param int $user_id The user ID. 118 * @param array $new_item { 119 * The details about the created password. 120 * 121 * @type string $uuid The unique identifier for the application password. 122 * @type string $app_id A UUID provided by the application to uniquely identify it. 123 * @type string $name The name of the application password. 124 * @type string $password A one-way hash of the password. 125 * @type int $created Unix timestamp of when the password was created. 126 * @type null $last_used Null. 127 * @type null $last_ip Null. 128 * } 129 * @param string $new_password The unhashed generated application password. 130 * @param array $args { 131 * Arguments used to create the application password. 132 * 133 * @type string $name The name of the application password. 134 * @type string $app_id A UUID provided by the application to uniquely identify it. 135 * } 136 */ 137 do_action( 'wp_create_application_password', $user_id, $new_item, $new_password, $args ); 138 139 return array( $new_password, $new_item ); 140 } 141 142 /** 143 * Gets a user's application passwords. 144 * 145 * @since 5.6.0 146 * 147 * @param int $user_id User ID. 148 * @return array { 149 * The list of app passwords. 150 * 151 * @type array ...$0 { 152 * @type string $uuid The unique identifier for the application password. 153 * @type string $app_id A UUID provided by the application to uniquely identify it. 154 * @type string $name The name of the application password. 155 * @type string $password A one-way hash of the password. 156 * @type int $created Unix timestamp of when the password was created. 157 * @type int|null $last_used The Unix timestamp of the GMT date the application password was last used. 158 * @type string|null $last_ip The IP address the application password was last used by. 159 * } 160 * } 161 */ 162 public static function get_user_application_passwords( $user_id ) { 163 $passwords = get_user_meta( $user_id, static::USERMETA_KEY_APPLICATION_PASSWORDS, true ); 164 165 if ( ! is_array( $passwords ) ) { 166 return array(); 167 } 168 169 $save = false; 170 171 foreach ( $passwords as $i => $password ) { 172 if ( ! isset( $password['uuid'] ) ) { 173 $passwords[ $i ]['uuid'] = wp_generate_uuid4(); 174 $save = true; 175 } 176 } 177 178 if ( $save ) { 179 static::set_user_application_passwords( $user_id, $passwords ); 180 } 181 182 return $passwords; 183 } 184 185 /** 186 * Gets a user's application password with the given UUID. 187 * 188 * @since 5.6.0 189 * 190 * @param int $user_id User ID. 191 * @param string $uuid The password's UUID. 192 * @return array|null The application password if found, null otherwise. 193 */ 194 public static function get_user_application_password( $user_id, $uuid ) { 195 $passwords = static::get_user_application_passwords( $user_id ); 196 197 foreach ( $passwords as $password ) { 198 if ( $password['uuid'] === $uuid ) { 199 return $password; 200 } 201 } 202 203 return null; 204 } 205 206 /** 207 * Checks if an application password with the given name exists for this user. 208 * 209 * @since 5.7.0 210 * 211 * @param int $user_id User ID. 212 * @param string $name Application name. 213 * @return bool Whether the provided application name exists. 214 */ 215 public static function application_name_exists_for_user( $user_id, $name ) { 216 $passwords = static::get_user_application_passwords( $user_id ); 217 218 foreach ( $passwords as $password ) { 219 if ( strtolower( $password['name'] ) === strtolower( $name ) ) { 220 return true; 221 } 222 } 223 224 return false; 225 } 226 227 /** 228 * Updates an application password. 229 * 230 * @since 5.6.0 231 * 232 * @param int $user_id User ID. 233 * @param string $uuid The password's UUID. 234 * @param array $update Information about the application password to update. 235 * @return true|WP_Error True if successful, otherwise a WP_Error instance is returned on error. 236 */ 237 public static function update_application_password( $user_id, $uuid, $update = array() ) { 238 $passwords = static::get_user_application_passwords( $user_id ); 239 240 foreach ( $passwords as &$item ) { 241 if ( $item['uuid'] !== $uuid ) { 242 continue; 243 } 244 245 if ( ! empty( $update['name'] ) ) { 246 $update['name'] = sanitize_text_field( $update['name'] ); 247 } 248 249 $save = false; 250 251 if ( ! empty( $update['name'] ) && $item['name'] !== $update['name'] ) { 252 $item['name'] = $update['name']; 253 $save = true; 254 } 255 256 if ( $save ) { 257 $saved = static::set_user_application_passwords( $user_id, $passwords ); 258 259 if ( ! $saved ) { 260 return new WP_Error( 'db_error', __( 'Could not save application password.' ) ); 261 } 262 } 263 264 /** 265 * Fires when an application password is updated. 266 * 267 * @since 5.6.0 268 * 269 * @param int $user_id The user ID. 270 * @param array $item The updated app password details. 271 * @param array $update The information to update. 272 */ 273 do_action( 'wp_update_application_password', $user_id, $item, $update ); 274 275 return true; 276 } 277 278 return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) ); 279 } 280 281 /** 282 * Records that an application password has been used. 283 * 284 * @since 5.6.0 285 * 286 * @param int $user_id User ID. 287 * @param string $uuid The password's UUID. 288 * @return true|WP_Error True if the usage was recorded, a WP_Error if an error occurs. 289 */ 290 public static function record_application_password_usage( $user_id, $uuid ) { 291 $passwords = static::get_user_application_passwords( $user_id ); 292 293 foreach ( $passwords as &$password ) { 294 if ( $password['uuid'] !== $uuid ) { 295 continue; 296 } 297 298 // Only record activity once a day. 299 if ( $password['last_used'] + DAY_IN_SECONDS > time() ) { 300 return true; 301 } 302 303 $password['last_used'] = time(); 304 $password['last_ip'] = $_SERVER['REMOTE_ADDR']; 305 306 $saved = static::set_user_application_passwords( $user_id, $passwords ); 307 308 if ( ! $saved ) { 309 return new WP_Error( 'db_error', __( 'Could not save application password.' ) ); 310 } 311 312 return true; 313 } 314 315 // Specified Application Password not found! 316 return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) ); 317 } 318 319 /** 320 * Deletes an application password. 321 * 322 * @since 5.6.0 323 * 324 * @param int $user_id User ID. 325 * @param string $uuid The password's UUID. 326 * @return true|WP_Error Whether the password was successfully found and deleted, a WP_Error otherwise. 327 */ 328 public static function delete_application_password( $user_id, $uuid ) { 329 $passwords = static::get_user_application_passwords( $user_id ); 330 331 foreach ( $passwords as $key => $item ) { 332 if ( $item['uuid'] === $uuid ) { 333 unset( $passwords[ $key ] ); 334 $saved = static::set_user_application_passwords( $user_id, $passwords ); 335 336 if ( ! $saved ) { 337 return new WP_Error( 'db_error', __( 'Could not delete application password.' ) ); 338 } 339 340 /** 341 * Fires when an application password is deleted. 342 * 343 * @since 5.6.0 344 * 345 * @param int $user_id The user ID. 346 * @param array $item The data about the application password. 347 */ 348 do_action( 'wp_delete_application_password', $user_id, $item ); 349 350 return true; 351 } 352 } 353 354 return new WP_Error( 'application_password_not_found', __( 'Could not find an application password with that id.' ) ); 355 } 356 357 /** 358 * Deletes all application passwords for the given user. 359 * 360 * @since 5.6.0 361 * 362 * @param int $user_id User ID. 363 * @return int|WP_Error The number of passwords that were deleted or a WP_Error on failure. 364 */ 365 public static function delete_all_application_passwords( $user_id ) { 366 $passwords = static::get_user_application_passwords( $user_id ); 367 368 if ( $passwords ) { 369 $saved = static::set_user_application_passwords( $user_id, array() ); 370 371 if ( ! $saved ) { 372 return new WP_Error( 'db_error', __( 'Could not delete application passwords.' ) ); 373 } 374 375 foreach ( $passwords as $item ) { 376 /** This action is documented in wp-includes/class-wp-application-passwords.php */ 377 do_action( 'wp_delete_application_password', $user_id, $item ); 378 } 379 380 return count( $passwords ); 381 } 382 383 return 0; 384 } 385 386 /** 387 * Sets a user's application passwords. 388 * 389 * @since 5.6.0 390 * 391 * @param int $user_id User ID. 392 * @param array $passwords Application passwords. 393 * 394 * @return bool 395 */ 396 protected static function set_user_application_passwords( $user_id, $passwords ) { 397 return update_user_meta( $user_id, static::USERMETA_KEY_APPLICATION_PASSWORDS, $passwords ); 398 } 399 400 /** 401 * Sanitizes and then splits a password into smaller chunks. 402 * 403 * @since 5.6.0 404 * 405 * @param string $raw_password The raw application password. 406 * @return string The chunked password. 407 */ 408 public static function chunk_password( $raw_password ) { 409 $raw_password = preg_replace( '/[^a-z\d]/i', '', $raw_password ); 410 411 return trim( chunk_split( $raw_password, 4, ' ' ) ); 412 } 413 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |