Файловый менеджер - Редактировать - /home/beautybuzzbeyond/public_html/wp-content/plugins/application-passwords/class.application-passwords.php
Назад
<?php /** * Class for displaying, modifying, & sanitizing application passwords. * * @since 0.1-dev * * @package Two_Factor */ class Application_Passwords { /** * The user meta application password key. * @type string */ const USERMETA_KEY_APPLICATION_PASSWORDS = '_application_passwords'; /** * The length of generated application passwords. * * @type integer */ const PW_LENGTH = 24; /** * Add various hooks. * * @since 0.1-dev * * @access public * @static */ public static function add_hooks() { add_filter( 'authenticate', array( __CLASS__, 'authenticate' ), 10, 3 ); add_action( 'show_user_profile', array( __CLASS__, 'show_user_profile' ) ); add_action( 'edit_user_profile', array( __CLASS__, 'show_user_profile' ) ); add_action( 'rest_api_init', array( __CLASS__, 'rest_api_init' ) ); add_filter( 'determine_current_user', array( __CLASS__, 'rest_api_auth_handler' ), 20 ); add_filter( 'wp_rest_server_class', array( __CLASS__, 'wp_rest_server_class' ) ); add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ) ); add_action( 'admin_post_authorize_application_password', array( __CLASS__, 'authorize_application_password' ) ); self::fallback_populate_username_password(); } /** * Prevent caching of unauthenticated status. See comment below. * * We don't actually care about the `wp_rest_server_class` filter, it just * happens right after the constant we do care about is defined. * * @since 0.1-dev * * @access public * @static */ public static function wp_rest_server_class( $class ) { global $current_user; if ( defined( 'REST_REQUEST' ) && REST_REQUEST && $current_user instanceof WP_User && 0 === $current_user->ID ) { /* * For our authentication to work, we need to remove the cached lack * of a current user, so the next time it checks, we can detect that * this is a rest api request and allow our override to happen. This * is because the constant is defined later than the first get current * user call may run. */ $current_user = null; } return $class; } /** * Handle declaration of REST API endpoints. * * @since 0.1-dev * * @access public * @static */ public static function rest_api_init() { // List existing application passwords. register_rest_route( '2fa/v1', '/application-passwords/(?P<user_id>[\d]+)', array( 'methods' => WP_REST_Server::READABLE, 'callback' => __CLASS__ . '::rest_list_application_passwords', 'permission_callback' => __CLASS__ . '::rest_edit_user_callback', ) ); // Add new application passwords. register_rest_route( '2fa/v1', '/application-passwords/(?P<user_id>[\d]+)/add', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => __CLASS__ . '::rest_add_application_password', 'permission_callback' => __CLASS__ . '::rest_edit_user_callback', 'args' => array( 'name' => array( 'required' => true, ), ), ) ); // Delete an application password. register_rest_route( '2fa/v1', '/application-passwords/(?P<user_id>[\d]+)/(?P<slug>[\da-fA-F]{12})', array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => __CLASS__ . '::rest_delete_application_password', 'permission_callback' => __CLASS__ . '::rest_edit_user_callback', ) ); // Delete all application passwords for a given user. register_rest_route( '2fa/v1', '/application-passwords/(?P<user_id>[\d]+)', array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => __CLASS__ . '::rest_delete_all_application_passwords', 'permission_callback' => __CLASS__ . '::rest_edit_user_callback', ) ); // Some hosts that run PHP in FastCGI mode won't be given the Authentication header. register_rest_route( '2fa/v1', '/test-basic-authorization-header/', array( 'methods' => WP_REST_Server::READABLE . ', ' . WP_REST_Server::CREATABLE, 'callback' => __CLASS__ . '::rest_test_basic_authorization_header', 'permission_callback' => '__return_true', ) ); } /** * REST API endpoint to list existing application passwords for a user. * * @since 0.1-dev * * @access public * @static * * @param $data * * @return array */ public static function rest_list_application_passwords( $data ) { $application_passwords = self::get_user_application_passwords( $data['user_id'] ); $with_slugs = array(); if ( $application_passwords ) { foreach ( $application_passwords as $item ) { $item['slug'] = self::password_unique_slug( $item ); unset( $item['raw'] ); unset( $item['password'] ); $item['created'] = date( get_option( 'date_format', 'r' ), $item['created'] ); if ( empty( $item['last_used'] ) ) { $item['last_used'] = '—'; } else { $item['last_used'] = date( get_option( 'date_format', 'r' ), $item['last_used'] ); } if ( empty( $item['last_ip'] ) ) { $item['last_ip'] = '—'; } $with_slugs[ $item['slug'] ] = $item; } } return $with_slugs; } /** * REST API endpoint to add a new application password for a user. * * @since 0.1-dev * * @access public * @static * * @param $data * * @return array */ public static function rest_add_application_password( $data ) { list( $new_password, $new_item ) = self::create_new_application_password( $data['user_id'], $data['name'] ); // Some tidying before we return it. $new_item['slug'] = self::password_unique_slug( $new_item ); $new_item['created'] = date( get_option( 'date_format', 'r' ), $new_item['created'] ); $new_item['last_used'] = '—'; $new_item['last_ip'] = '—'; unset( $new_item['password'] ); return array( 'row' => $new_item, 'password' => self::chunk_password( $new_password ) ); } /** * REST API endpoint to delete a given application password. * * @since 0.1-dev * * @access public * @static * * @param $data * * @return bool */ public static function rest_delete_application_password( $data ) { return self::delete_application_password( $data['user_id'], $data['slug'] ); } /** * REST API endpoint to delete all of a user's application passwords. * * @since 0.1-dev * * @access public * @static * * @param $data * * @return int The number of deleted passwords */ public static function rest_delete_all_application_passwords( $data ) { return self::delete_all_application_passwords( $data['user_id'] ); } /** * Whether or not the current user can edit the specified user. * * @since 0.1-dev * * @access public * @static * * @param $data * * @return bool */ public static function rest_edit_user_callback( $data ) { return current_user_can( 'edit_user', $data['user_id'] ); } /** * Loosely Based on https://github.com/WP-API/Basic-Auth/blob/master/basic-auth.php * * @since 0.1-dev * * @access public * @static * * @param $input_user * * @return WP_User|bool */ public static function rest_api_auth_handler( $input_user ){ // Don't authenticate twice. if ( ! empty( $input_user ) ) { return $input_user; } // Check that we're trying to authenticate if ( ! isset( $_SERVER['PHP_AUTH_USER'] ) ) { return $input_user; } $user = self::authenticate( $input_user, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ); if ( $user instanceof WP_User ) { return $user->ID; } // If it wasn't a user what got returned, just pass on what we had received originally. return $input_user; } /** * Test whether PHP can see Basic Authorization headers passed to the web server. * * @return WP_Error|array */ public static function rest_test_basic_authorization_header() { $response = array(); if ( isset( $_SERVER['PHP_AUTH_USER'] ) ) { $response['PHP_AUTH_USER'] = $_SERVER['PHP_AUTH_USER']; } if ( isset( $_SERVER['PHP_AUTH_PW'] ) ) { $response['PHP_AUTH_PW'] = $_SERVER['PHP_AUTH_PW']; } if ( empty( $response ) ) { return new WP_Error( 'no-credentials', __( 'No HTTP Basic Authorization credentials were found submitted with this request.' ), array( 'status' => 404 ) ); } return $response; } /** * Some servers running in CGI or FastCGI mode don't pass the Authorization * header on to WordPress. If it's been rewritten to the `REMOTE_USER` header, * fill in the proper $_SERVER variables instead. */ public static function fallback_populate_username_password() { // If we don't have anything to pull from, return early. if ( ! isset( $_SERVER['REMOTE_USER'] ) && ! isset( $_SERVER['REDIRECT_REMOTE_USER'] ) ) { return; } // If either PHP_AUTH key is already set, do nothing. if ( isset( $_SERVER['PHP_AUTH_USER'] ) || isset( $_SERVER['PHP_AUTH_PW'] ) ) { return; } // From our prior conditional, one of these must be set. $header = isset( $_SERVER['REMOTE_USER'] ) ? $_SERVER['REMOTE_USER'] : $_SERVER['REDIRECT_REMOTE_USER']; // Test to make sure the pattern matches expected. if ( ! preg_match( '%^Basic [a-z\d/+]*={0,2}$%i', $header ) ) { return; } // Removing `Basic ` the token would start six characters in. $token = substr( $header, 6 ); $userpass = base64_decode( $token ); list( $user, $pass ) = explode( ':', $userpass ); // Now shove them in the proper keys where we're expecting later on. $_SERVER['PHP_AUTH_USER'] = $user; $_SERVER['PHP_AUTH_PW'] = $pass; return array( $user, $pass ); } /** * Check if the current request is an API request * for which we should check the HTTP Auth headers. * * @return boolean */ public static function is_api_request() { // Process the authentication only after the APIs have been initialized. return ( ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ); } /** * Filter the user to authenticate. * * @since 0.1-dev * * @access public * @static * * @param WP_User $input_user User to authenticate. * @param string $username User login. * @param string $password User password. * * @return mixed */ public static function authenticate( $input_user, $username, $password ) { if ( ! apply_filters( 'application_password_is_api_request', self::is_api_request() ) ) { return $input_user; } $user = get_user_by( 'login', $username ); if ( ! $user && is_email( $username ) ) { $user = get_user_by( 'email', $username ); } // If the login name is invalid, short circuit. if ( ! $user ) { return $input_user; } /* * Strip out anything non-alphanumeric. This is so passwords can be used with * or without spaces to indicate the groupings for readability. * * Generated application passwords are exclusively alphanumeric. */ $password = preg_replace( '/[^a-z\d]/i', '', $password ); $hashed_passwords = get_user_meta( $user->ID, self::USERMETA_KEY_APPLICATION_PASSWORDS, true ); // If there aren't any, there's nothing to return. Avoid the foreach. if ( empty( $hashed_passwords ) ) { return $input_user; } foreach ( $hashed_passwords as $key => $item ) { if ( wp_check_password( $password, $item['password'], $user->ID ) ) { $item['last_used'] = time(); $item['last_ip'] = $_SERVER['REMOTE_ADDR']; $hashed_passwords[ $key ] = $item; update_user_meta( $user->ID, self::USERMETA_KEY_APPLICATION_PASSWORDS, $hashed_passwords ); do_action( 'application_password_did_authenticate', $user, $item ); return $user; } } // By default, return what we've been passed. return $input_user; } /** * Registers the hidden admin page to handle auth. */ public static function admin_menu() { add_submenu_page( null, __( 'Approve Application' ), null, 'exist', 'auth_app', array( __CLASS__, 'auth_app_page' ) ); } /** * Page for authorizing applications. */ public static function auth_app_page() { $app_name = ! empty( $_GET['app_name'] ) ? $_GET['app_name'] : ''; // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification $success_url = ! empty( $_GET['success_url'] ) ? $_GET['success_url'] : null; // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification $reject_url = ! empty( $_GET['reject_url'] ) ? $_GET['reject_url'] : $success_url; // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification $user = wp_get_current_user(); wp_enqueue_script( 'auth-app', plugin_dir_url( __FILE__ ) . 'auth-app.js', array(), APPLICATION_PASSWORDS_VERSION, true ); wp_localize_script( 'auth-app', 'authApp', array( 'root' => esc_url_raw( rest_url() ), 'namespace' => '2fa/v1', 'nonce' => wp_create_nonce( 'wp_rest' ), 'user_id' => $user->ID, 'user_login' => $user->user_login, 'success' => $success_url, 'reject' => $reject_url ? $reject_url : admin_url(), 'strings' => array( // translators: application, password. 'new_pass' => esc_html_x( 'Your new password for %1$s is: %2$s', 'application, password' ), ), ) ); ?> <div class="wrap"> <h1><?php esc_html_e( 'Authorize Application' ); ?></h1> <div class="card js-auth-app-card"> <h2 class="title"><?php esc_html_e( 'An application would like to connect to your account.' ); ?></h2> <?php if ( $app_name ) : ?> <p> <?php // translators: application name. printf( esc_html__( 'Would you like to give the application identifying itself as %1$s access to your account? You should only do this if you trust the app in question.' ), '<strong>' . esc_html( $app_name ) . '</strong>' ); ?> </p> <?php else : ?> <p><?php esc_html_e( 'Would you like to give this application access to your account? You should only do this if you trust the app in question.' ); ?></p> <?php endif; ?> <form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post"> <?php wp_nonce_field( 'authorize_application_password' ); ?> <input type="hidden" name="action" value="authorize_application_password" /> <input type="hidden" name="success_url" value="<?php echo esc_url( $success_url ); ?>" /> <input type="hidden" name="reject_url" value="<?php echo esc_url( $reject_url ); ?>" /> <label for="app_name"><?php esc_html_e( 'Application Title:' ); ?></label> <input type="text" id="app_name" name="app_name" value="<?php echo esc_attr( $app_name ); ?>" placeholder="<?php esc_attr_e( 'Name this connection…' ); ?>" required /> <p><?php submit_button( __( 'Yes, I approve of this connection.' ), 'primary', 'approve', false ); ?> <br /><em> <?php if ( $success_url ) { printf( // translators: url. esc_html_x( 'You will be sent to %1$s', '%1$s is a url' ), '<strong><kbd>' . esc_html( add_query_arg( array( 'username' => $user->user_login, 'password' => '[------]', ), $success_url ) ) . '</kbd></strong>' ); } else { esc_html_e( 'You will be given a password to manually enter into the application in question.' ); } ?> </em> </p> <p><?php submit_button( __( 'No, I do not approve of this connection.' ), 'secondary', 'reject', false ); ?> <br /><em> <?php if ( $reject_url ) { printf( // translators: url. esc_html_x( 'You will be sent to %1$s', '%1$s is a url' ), '<strong><kbd>' . esc_html( add_query_arg( array( 'success' => 'false', ), $reject_url ) ) . '</kbd></strong>' ); } else { esc_html_e( 'You will be returned to the WordPress Dashboard, and we will never speak of this again.' ); } ?> </em> </p> </form> </div> </div> <?php } /** * Handle non-JS submissions via traditional posting. */ public static function authorize_application_password() { check_admin_referer( 'authorize_application_password' ); $success_url = $_POST['success_url']; $reject_url = $_POST['reject_url']; $app_name = $_POST['app_name']; $redirect = admin_url(); if ( isset( $_POST['reject'] ) ) { if ( $reject_url ) { // Explicitly not using wp_safe_redirect b/c sends to arbitrary domain. $redirect = esc_url_raw( add_query_arg( 'success', 'false', $reject_url ) ); } } elseif ( isset( $_POST['approve'] ) ) { list( $new_password, $new_item ) = self::create_new_application_password( get_current_user_id(), $app_name ); if ( empty( $success_url ) ) { wp_die( '<h1>' . esc_html__( 'Your New Application Password:' ) . '</h1><h3><kbd>' . esc_html( self::chunk_password( $new_password ) ) . '</kbd></h3>' ); } $redirect = add_query_arg( array( 'username' => wp_get_current_user()->user_login, 'password' => $new_password, ), $success_url ); } wp_redirect( $redirect ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect exit; } /** * Display the application password section in a users profile. * * This executes during the `show_user_security_settings` action. * * @since 0.1-dev * * @access public * @static * * @param WP_User $user WP_User object of the logged-in user. */ public static function show_user_profile( $user ) { wp_enqueue_style( 'application-passwords-css', plugin_dir_url( __FILE__ ) . 'application-passwords.css', array(), APPLICATION_PASSWORDS_VERSION ); wp_enqueue_script( 'application-passwords-js', plugin_dir_url( __FILE__ ) . 'application-passwords.js', array(), APPLICATION_PASSWORDS_VERSION, true ); wp_localize_script( 'application-passwords-js', 'appPass', array( 'root' => esc_url_raw( rest_url() ), 'namespace' => '2fa/v1', 'nonce' => wp_create_nonce( 'wp_rest' ), 'user_id' => $user->ID, 'text' => array( 'no_credentials' => __( 'Due to a potential server misconfiguration, it seems that HTTP Basic Authorization may not work for the REST API on this site: `Authorization` headers are not being sent to WordPress by the web server. <a href="https://github.com/georgestephanis/application-passwords/wiki/Basic-Authorization-Header----Missing">You can learn more about this problem, and a possible solution, on our GitHub Wiki.</a>' ), 'revoke_password' => esc_attr__( 'Are you sure you want to revoke this password? This action cannot be undone.' ), 'revoke_all_passwords' => esc_attr__( 'Are you sure you want to revoke all passwords? This action cannot be undone.' ), ), ) ); ?> <div class="application-passwords hide-if-no-js" id="application-passwords-section"> <h2 id="application-passwords"><?php esc_html_e( 'Application Passwords' ); ?></h2> <p><?php esc_html_e( 'Application passwords allow authentication via non-interactive systems, such as XMLRPC or the REST API, without providing your actual password. Application passwords can be easily revoked. They cannot be used for traditional logins to your website.' ); ?></p> <div class="create-application-password"> <input type="text" size="30" name="new_application_password_name" placeholder="<?php esc_attr_e( 'New Application Password Name' ); ?>" class="input" /> <?php submit_button( __( 'Add New' ), 'secondary', 'do_new_application_password', false ); ?> </div> <div class="application-passwords-list-table-wrapper"> <?php require( dirname( __FILE__ ) . '/class.application-passwords-list-table.php' ); $application_passwords_list_table = new Application_Passwords_List_Table(); $application_passwords_list_table->items = array_reverse( self::get_user_application_passwords( $user->ID ) ); $application_passwords_list_table->prepare_items(); $application_passwords_list_table->display(); ?> </div> </div> <script type="text/html" id="tmpl-new-application-password"> <div class="new-application-password notification-dialog-wrap"> <div class="app-pass-dialog-background notification-dialog-background"> <div class="app-pass-dialog notification-dialog"> <div class="new-application-password-content"> <?php printf( // translators: application, password. esc_html_x( 'Your new password for %1$s is: %2$s', 'application, password' ), '<strong>{{ data.name }}</strong>', '<kbd>{{ data.password }}</kbd>' ); ?> </div> <p><?php esc_attr_e( 'Be sure to save this in a safe location. You will not be able to retrieve it.' ); ?></p> <button class="button button-primary application-password-modal-dismiss"><?php esc_attr_e( 'Dismiss' ); ?></button> </div> </div> </div> </script> <script type="text/html" id="tmpl-application-password-row"> <tr data-slug="{{ data.slug }}"> <td class="name column-name has-row-actions column-primary" data-colname="<?php esc_attr_e( 'Name' ); ?>"> {{ data.name }} <button type="button" class="toggle-row"><span class="screen-reader-text"><?php esc_html_e( 'Show more details' ); ?></span></button> </td> <td class="created column-created" data-colname="<?php esc_attr_e( 'Created' ); ?>"> {{ data.created }} </td> <td class="last_used column-last_used" data-colname="<?php esc_attr_e( 'Last Used' ); ?>"> {{ data.last_used }} </td> <td class="last_ip column-last_ip" data-colname="<?php esc_attr_e( 'Last IP' ); ?>"> {{ data.last_ip }} </td> <td class="revoke column-revoke" data-colname="<?php esc_attr_e( 'Revoke' ); ?>"> <input type="submit" name="revoke-application-password" class="button delete" value="<?php esc_attr_e( 'Revoke' ); ?>"> </td> </tr> </script> <script type="text/html" id="tmpl-application-password-notice"> <div class="notice notice-{{ data.type }}"><p>{{{ data.message }}}</p></div> </script> <?php } /** * Generate a new application password. * * @since 0.1-dev * * @access public * @static * * @param int $user_id User ID. * @param string $name Password name. * @return array The first key in the array is the new password, the second is its row in the table. */ public static function create_new_application_password( $user_id, $name ) { $new_password = wp_generate_password( self::PW_LENGTH, false ); $hashed_password = wp_hash_password( $new_password ); $new_item = array( 'name' => $name, 'password' => $hashed_password, 'created' => time(), 'last_used' => null, 'last_ip' => null, ); $passwords = self::get_user_application_passwords( $user_id ); if ( ! $passwords ) { $passwords = array(); } $passwords[] = $new_item; self::set_user_application_passwords( $user_id, $passwords ); return array( $new_password, $new_item ); } /** * Delete a specified application password. * * @since 0.1-dev * * @access public * @static * * @see Application_Passwords::password_unique_slug() * * @param int $user_id User ID. * @param string $slug The generated slug of the password in question. * @return bool Whether the password was successfully found and deleted. */ public static function delete_application_password( $user_id, $slug ) { $passwords = self::get_user_application_passwords( $user_id ); foreach ( $passwords as $key => $item ) { if ( self::password_unique_slug( $item ) === $slug ) { unset( $passwords[ $key ] ); self::set_user_application_passwords( $user_id, $passwords ); return true; } } // Specified Application Password not found! return false; } /** * Deletes all application passwords for the given user. * * @since 0.1-dev * * @access public * @static * * @param int $user_id User ID. * @return int The number of passwords that were deleted. */ public static function delete_all_application_passwords( $user_id ) { $passwords = self::get_user_application_passwords( $user_id ); if ( is_array( $passwords ) ) { self::set_user_application_passwords( $user_id, array() ); return sizeof( $passwords ); } return 0; } /** * Generate a unique repeatable slug from the hashed password, name, and when it was created. * * @since 0.1-dev * * @access public * @static * * @param array $item The current item. * @return string */ public static function password_unique_slug( $item ) { $concat = $item['name'] . '|' . $item['password'] . '|' . $item['created']; $hash = md5( $concat ); return substr( $hash, 0, 12 ); } /** * Sanitize and then split a password into smaller chunks. * * @since 0.1-dev * * @access public * @static * * @param string $raw_password Users raw password. * @return string */ public static function chunk_password( $raw_password ) { $raw_password = preg_replace( '/[^a-z\d]/i', '', $raw_password ); return trim( chunk_split( $raw_password, 4, ' ' ) ); } /** * Get a users application passwords. * * @since 0.1-dev * * @access public * @static * * @param int $user_id User ID. * @return array */ public static function get_user_application_passwords( $user_id ) { $passwords = get_user_meta( $user_id, self::USERMETA_KEY_APPLICATION_PASSWORDS, true ); if ( ! is_array( $passwords ) ) { return array(); } return $passwords; } /** * Set a users application passwords. * * @since 0.1-dev * * @access public * @static * * @param int $user_id User ID. * @param array $passwords Application passwords. * * @return bool */ public static function set_user_application_passwords( $user_id, $passwords ) { return update_user_meta( $user_id, self::USERMETA_KEY_APPLICATION_PASSWORDS, $passwords ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.0.30 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка