=> 'edit' ] ); $response = rest_do_request( $request ); if ( ! $response->is_error() ) { wp_add_inline_script( 'itsec-core-profile-front', sprintf( "wp.data.dispatch('%s').receiveCurrentUserId( %d );", 'ithemes-security/core', get_current_user_id() ) ); wp_add_inline_script( 'itsec-core-profile-front', sprintf( "wp.data.dispatch('%s').receiveUser( %s );", 'ithemes-security/core', wp_json_encode( rest_get_server()->response_to_data( $response, false ) ) ) ); } foreach ( ITSEC_Modules::get_active_modules_to_run() as $module ) { $handle = "itsec-{$module}-profile"; if ( wp_script_is( $handle, 'registered' ) ) { wp_enqueue_script( $handle ); } if ( wp_style_is( $handle, 'registered' ) ) { wp_enqueue_style( $handle ); } } /** * Fires when scripts are enqueued for the User Profile JS code. * * @param WP_User $user */ do_action( 'itsec_enqueue_profile', wp_get_current_user() ); } public function register_tools( Tools_Registry $registry ) { $registry->register( new class( 'set-encryption-key', ITSEC_Modules::get_config( 'core' ) ) extends Config_Tool { public function run( array $form = [] ): Result { if ( ITSEC_Lib_Encryption::is_available() && ! $form['confirm'] ) { return Result::error( new WP_Error( 'itsec.tool.set-encryption-key.unconfirmed', __( 'You must check “Confirm Reset Key” to continue.', 'better-wp-security' ) ) ); } try { $key = ITSEC_Lib_Encryption::generate_secret(); } catch ( RuntimeException $e ) { return Result::error( new WP_Error( 'itsec.tool.set-encryption-key.cannot-generate-key', __( 'Could not generate a random encryption key.', 'better-wp-security' ) ) ); } $saved = ITSEC_Lib_Encryption::save_secret_key( $key ); if ( ! $saved->is_success() ) { return $saved; } if ( ITSEC_Lib_Encryption::is_available() ) { $rotated = ITSEC_Lib_Encryption::rotate_with_new_key( $key ); return Result::combine( $saved, $rotated ); } return $saved; } public function get_help(): string { $help = parent::get_help(); if ( ! ITSEC_Lib_Encryption::is_available() ) { return $help; } $help .= ' ' . __( 'Your site already has a valid encryption key. Use this tool to automatically re-encrypt all secrets with a new encryption key.', 'better-wp-security' ); $help .= ' ' . __( 'This may take a while. If available, try running this tool with WP CLI for better performance.', 'better-wp-security' ); return $help; } public function get_form(): array { if ( ITSEC_Lib_Encryption::is_available() ) { return parent::get_form(); } return []; } public function is_available(): bool { return ITSEC_Files::can_write_to_files(); } } ); $registry->register( new class( 'rotate-encryption-key', ITSEC_Modules::get_config( 'core' ) ) extends Config_Tool { public function run( array $form = [] ): Result { $old_key = $form['previous']; return ITSEC_Lib_Encryption::rotate_with_old_key( $old_key ); } public function is_available(): bool { return ITSEC_Lib_Encryption::has_encryption_key_changed() && ITSEC_Lib_Encryption::is_available(); } } ); $registry->register( new class( 'create-mu-plugin', ITSEC_Modules::get_config( 'core' ) ) extends Config_Tool { public function run( array $form = [] ): Result { $template = ITSEC_Lib_File::read( __DIR__ . '/security-loader.txt' ); if ( is_wp_error( $template ) ) { return Result::error( $template ); } $basename = plugin_basename( ITSEC_Core::get_plugin_file() ); if ( ! file_exists( WP_CONTENT_DIR . '/plugins/' . $basename ) ) { return Result::error( new WP_Error( 'itsec.tool.create-mu-plugin.unknown-installation', __( 'Could not determine the correct path to load Solid Security.', 'better-wp-security' ) ) ); } $contents = sprintf( $template, $basename ); $path = WP_CONTENT_DIR . '/mu-plugins/000-solid-security-loader.php'; $written = ITSEC_Lib_File::write( $path, $contents ); if ( is_wp_error( $written ) ) { return Result::error( $written ); } return Result::success()->add_success_message( __( 'Created MU-Plugin loader.', 'better-wp-security' ) ); } public function is_available(): bool { return ! defined( 'ITSEC_LOAD_EARLY' ) || ! ITSEC_LOAD_EARLY; } } ); $registry->register( new class( 'remove-mu-plugin', ITSEC_Modules::get_config( 'core' ) ) extends Config_Tool { public function run( array $form = [] ): Result { $path = WP_CONTENT_DIR . '/mu-plugins/000-solid-security-loader.php'; $removed = ITSEC_Lib_File::remove( $path ); if ( is_wp_error( $removed ) ) { return Result::error( $removed ); } return Result::success()->add_success_message( __( 'Removed MU-Plugin loader.', 'better-wp-security' ) ); } public function is_available(): bool { return file_exists( WP_CONTENT_DIR . '/mu-plugins/000-solid-security-loader.php' ); } } ); } public function rotate_encrypted_user_keys( User_Key_Rotator $rotator, Result $result ) { global $wpdb; $user_meta_keys = array_reduce( ITSEC_Modules::get_config_list( ':all' ), function ( $keys, Module_Config $config ) { array_push( $keys, ...$config->get_encrypted_user_meta_keys() ); return $keys; }, [] ); if ( ! $user_meta_keys ) { return; } $in_sql = implode( ', ', array_fill( 0, count( $user_meta_keys ), '%s' ) ); $query = "SELECT * FROM {$wpdb->usermeta} WHERE meta_key IN (" . $in_sql . ")"; $rows = $wpdb->get_results( $wpdb->prepare( $query, $user_meta_keys ) ); if ( $wpdb->last_error ) { $result->add_warning_message( sprintf( __( 'Could not fetch user metadata to update: %s', 'better-wp-security' ), $wpdb->last_error ) ); return; } $users_to_clear = []; foreach ( $rows as $row ) { $meta_id = (int) $row->umeta_id; $user_id = (int) $row->user_id; $meta_key = (string) $row->meta_key; $meta_value = (string) $row->meta_value; if ( ! ITSEC_Lib_Encryption::is_encrypted( $meta_value ) ) { continue; } try { $rotated = $rotator( $meta_value, $user_id ); do_action( 'update_user_meta', $meta_id, $user_id, $meta_key, $rotated ); $updated = $wpdb->update( $wpdb->usermeta, [ 'meta_value' => $rotated ], [ 'umeta_id' => $meta_id ], '%s', '%d' ); if ( $updated ) { do_action( 'updated_user_meta', $meta_id, $user_id, $meta_key, $rotated ); $users_to_clear[ $user_id ] = true; } else { $result->add_warning_message( sprintf( __( 'Could not rotate \'%1$s\' for \'%2$d\': %3$s', 'better-wp-security' ), $meta_key, $user_id, $wpdb->last_error ?: __( 'User meta not updated.', 'better-wp-security' ) ) ); } } catch ( RuntimeException $e ) { $result->add_warning_message( sprintf( __( 'Could not rotate \'%1$s\' for \'%2$d\': %3$s', 'better-wp-security' ), $meta_key, $user_id, $e->getMessage() ) ); } } foreach ( array_flip( $users_to_clear ) as $user_id ) { wp_cache_delete( $user_id, 'user_meta' ); } } public function enable_encryption() { if ( ITSEC_Lib_Encryption::is_available() || ! ITSEC_Files::can_write_to_files() ) { return; } if ( ! ITSEC_Lib_Feature_Flags::is_enabled( 'enable_encryption' ) ) { return; } if ( get_site_option( 'itsec-enable-encryption-failed' ) ) { return; } try { ITSEC_Log::add_debug( 'core', 'try-enable-encryption' ); $secret = ITSEC_Lib_Encryption::generate_secret(); $result = ITSEC_Lib_Encryption::save_secret_key( $secret ); if ( $result->is_success() ) { ITSEC_Log::add_debug( 'core', 'enabled-encryption' ); } else { update_site_option( 'itsec-enable-encryption-failed', ITSEC_Core::get_current_time_gmt() ); ITSEC_Log::add_warning( 'core', 'enable-encryption-failed', $result->get_error() ); } } catch ( \Exception $e ) { update_site_option( 'itsec-enable-encryption-failed', ITSEC_Core::get_current_time_gmt() ); ITSEC_Log::add_warning( 'core', 'enable-encryption-failed', new WP_Error( 'itsec.encryption.cannot-generate-secret', $e->getMessage() ) ); } } }