From 238bddd4eb0f1d3607fbb3dcf1cf91c389887997 Mon Sep 17 00:00:00 2001 From: thanghv Date: Wed, 28 Feb 2024 00:43:57 +0700 Subject: [PATCH] * Added: Support for the new API Backups providers - cPanel and Plesk * Updated: Updated the phpSecLib library to enhance security and performance. --- class/class-mainwp-child-api-backups.php | 119 +++++++++++++++ class/class-mainwp-child-branding.php | 5 +- class/class-mainwp-child-cache-purge.php | 25 ++-- class/class-mainwp-child-callable.php | 14 +- class/class-mainwp-child-ithemes-security.php | 6 + class/class-mainwp-child-stats.php | 7 +- class/class-mainwp-child.php | 7 +- class/class-mainwp-clone.php | 3 +- class/class-mainwp-connect.php | 75 ++++++++-- class/class-mainwp-custom-post-type.php | 16 +- class/class-mainwp-security.php | 8 +- class/class-mainwp-utility.php | 45 +++++- libs/phpseclib/composer.lock | 12 +- libs/phpseclib/vendor/autoload.php | 19 ++- .../phpseclib/vendor/composer/ClassLoader.php | 137 +++++++++--------- .../vendor/composer/InstalledVersions.php | 31 ++-- .../vendor/composer/autoload_real.php | 35 ++--- .../vendor/composer/autoload_static.php | 8 +- libs/phpseclib/vendor/composer/installed.json | 14 +- libs/phpseclib/vendor/composer/installed.php | 16 +- .../vendor/phpseclib/phpseclib/README.md | 3 +- .../phpseclib/Crypt/Common/AsymmetricKey.php | 6 +- .../Crypt/Common/Formats/Keys/PKCS8.php | 3 +- .../phpseclib/Crypt/Common/SymmetricKey.php | 2 + .../Crypt/EC/Formats/Signature/IEEE.php | 66 +++++++++ .../phpseclib/phpseclib/Crypt/RSA.php | 1 + .../phpseclib/phpseclib/Crypt/Rijndael.php | 4 +- .../phpseclib/phpseclib/File/ASN1.php | 3 +- .../phpseclib/phpseclib/File/X509.php | 3 +- .../phpseclib/phpseclib/Math/BigInteger.php | 17 ++- .../Math/BigInteger/Engines/Engine.php | 5 + .../phpseclib/Math/BigInteger/Engines/PHP.php | 15 ++ .../Math/BigInteger/Engines/PHP32.php | 6 +- .../Math/BigInteger/Engines/PHP64.php | 2 +- .../phpseclib/phpseclib/Math/BinaryField.php | 9 ++ .../phpseclib/Math/PrimeField/Integer.php | 9 +- .../phpseclib/phpseclib/Net/SFTP.php | 14 +- .../phpseclib/phpseclib/Net/SSH2.php | 108 ++++++++++++-- mainwp-child.php | 2 +- readme.txt | 8 +- 40 files changed, 663 insertions(+), 225 deletions(-) create mode 100644 class/class-mainwp-child-api-backups.php create mode 100644 libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/IEEE.php diff --git a/class/class-mainwp-child-api-backups.php b/class/class-mainwp-child-api-backups.php new file mode 100644 index 00000000..74e9f159 --- /dev/null +++ b/class/class-mainwp-child-api-backups.php @@ -0,0 +1,119 @@ +format( 'm-d-Y_H.i.s.A' ); + + // Build the uploads directory. + $wp_get_upload_dir = wp_get_upload_dir(); + $wp_upload_dir = $wp_get_upload_dir['basedir'] . '/mainwp/api_db_backups/'; + + // Build the full path to the backup file. + $gzip_full_path = $wp_upload_dir . $database_name . '_' . $site_url . '_' . $current_date_time . '.sql.gz'; + + // Create the directory if it doesn't exist. + if ( ! file_exists( $wp_upload_dir ) ) { //phpcs:ignore + mkdir( $wp_upload_dir, 0755, true ); //phpcs:ignore + } + + if ( function_exists( 'exec' ) ) { + // Create the backup file. hide from logs ( password ). + exec( "mysqldump --user={$user} --password='{$pass}' --host={$host} {$database_name} | gzip > {$gzip_full_path}", $output, $result ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec + } + + // Check if the backup was successful. + if ( 0 === $result ) { + // Success. + MainWP_Helper::write( + array( + 'result' => 'GOOD', + 'output' => $output, + 'res' => $result, + ) + ); + } else { + // Error. + MainWP_Helper::write( + array( + 'result' => 'ERROR', + 'output' => $output, + 'res' => $result, + ) + ); + } + } +} diff --git a/class/class-mainwp-child-branding.php b/class/class-mainwp-child-branding.php index 90a4e198..795c9a0d 100644 --- a/class/class-mainwp-child-branding.php +++ b/class/class-mainwp-child-branding.php @@ -583,7 +583,6 @@ public function admin_menu() { if ( 'T' === $opts['show_support'] ) { $title = $opts['contact_label']; if ( isset( $extra_setting['show_button_in'] ) && ( 2 === (int) $extra_setting['show_button_in'] || 3 === (int) $extra_setting['show_button_in'] ) ) { - $title = $opts['contact_label']; add_menu_page( $title, $title, @@ -600,9 +599,9 @@ public function admin_menu() { if ( isset( $extra_setting['show_button_in'] ) && ( 1 === (int) $extra_setting['show_button_in'] || 3 === (int) $extra_setting['show_button_in'] ) ) { add_submenu_page( - null, + 'admin.php', + $title, $title, - $opts['contact_label'], 'read', 'ContactSupport', array( diff --git a/class/class-mainwp-child-cache-purge.php b/class/class-mainwp-child-cache-purge.php index fd3f1b02..e5fe578a 100644 --- a/class/class-mainwp-child-cache-purge.php +++ b/class/class-mainwp-child-cache-purge.php @@ -834,15 +834,15 @@ public function sitegrounds_optimizer_auto_purge_cache() { public function cloudflair_auto_purge_cache() { // Credentials for Cloudflare. - $cust_email = get_option( 'mainwp_cloudflair_email' ); - $cust_xauth = get_option( 'mainwp_child_cloudflair_key' ); + $cust_email = get_option( 'mainwp_cloudflair_email', '' ); + $cust_xauth = get_option( 'mainwp_child_cloudflair_key', '' ); if ( ! empty( $cust_xauth ) ) { $cust_xauth = MainWP_Child_Keys_Manager::instance()->decrypt_string( $cust_xauth ); } $cust_domain = trim( str_replace( array( 'http://', 'https://', 'www.' ), '', get_option( 'siteurl' ) ), '/' ); // Check if we have all the required data. - if ( '' === $cust_email || '' === $cust_xauth || '' === $cust_domain ) { + if ( '' === $cust_email || '' === $cust_xauth ) { return; } @@ -1028,18 +1028,15 @@ public function record_results( $information ) { * @return string The url without subdomains (if any). */ public function strip_subdomains( $url ) { - - // credits to gavingmiller for maintaining this list. - $second_level_domains = wp_remote_get( 'https://raw.githubusercontent.com/gavingmiller/second-level-domains/master/SLDs.csv' ); - - // presume sld first ... - $possible_sld = implode( '.', array_slice( explode( '.', $url ), -2 ) ); - - // and then verify it. - if ( strpos( $second_level_domains, $possible_sld ) ) { - return implode( '.', array_slice( explode( '.', $url ), -3 ) ); + $parts = explode( '/', $url ); + $url_first = $parts[0]; // get first part. + $count = count( explode( '.', $url_first ) ); + $domain = ''; + if ( 4 <= $count ) { + $domain = implode( '.', array_slice( explode( '.', $url_first ), -3 ) ); } else { - return implode( '.', array_slice( explode( '.', $url ), -2 ) ); + $domain = implode( '.', array_slice( explode( '.', $url_first ), -2 ) ); } + return $domain; } } diff --git a/class/class-mainwp-child-callable.php b/class/class-mainwp-child-callable.php index 9eb4d325..a02f9cf4 100644 --- a/class/class-mainwp-child-callable.php +++ b/class/class-mainwp-child-callable.php @@ -98,7 +98,7 @@ class MainWP_Child_Callable { 'jetpack_scan' => 'jetpack_scan', 'delete_actions' => 'delete_actions', 'verify_action' => 'verify_action', - + 'api_backups_mysqldump' => 'api_backups_mysqldump', ); /** @@ -1090,4 +1090,16 @@ public function deactivate() { $information['deactivated'] = true; MainWP_Helper::write( $information ); } + + /** + * Method api_backups_mysqldump() + * + * Fire off the action() function. + * + * @uses MainWP_Child_Api_Backups::action() + * @used-by \MainWP\Extensions\ApiBackups\MainWP_API_Backups_3rd_Party::api_backups_mysqldump() + */ + public function api_backups_mysqldump() { + MainWP_Child_Api_Backups::instance()->api_backups_mysqldump(); + } } diff --git a/class/class-mainwp-child-ithemes-security.php b/class/class-mainwp-child-ithemes-security.php index c67b7931..c5cee318 100644 --- a/class/class-mainwp-child-ithemes-security.php +++ b/class/class-mainwp-child-ithemes-security.php @@ -461,6 +461,12 @@ public function save_settings() { foreach ( $settings as $key => $val ) { $current_settings[$key] = $val; } + if('two-factor' === $module ){ + $active = \ITSEC_Modules::is_active( 'two-factor' ); + if(!$active){ + \ITSEC_Modules::activate( 'two-factor' ); + } + } \ITSEC_Modules::set_settings( $module, $current_settings ); $updated = true; } diff --git a/class/class-mainwp-child-stats.php b/class/class-mainwp-child-stats.php index 35a0b12f..6771e8a6 100644 --- a/class/class-mainwp-child-stats.php +++ b/class/class-mainwp-child-stats.php @@ -272,8 +272,11 @@ public function get_site_stats( $information = array(), $exit_done = true ) { } if ( ! empty( $_POST['primaryBackup'] ) ) { - $primary_bk = ! empty( $_POST['primaryBackup'] ) ? sanitize_text_field( wp_unslash( $_POST['primaryBackup'] ) ) : ''; - $information['primaryLasttimeBackup'] = MainWP_Utility::get_lasttime_backup( $primary_bk ); + $primary_bk = ! empty( $_POST['primaryBackup'] ) ? sanitize_text_field( wp_unslash( $_POST['primaryBackup'] ) ) : ''; + $last_time = MainWP_Utility::get_lasttime_backup( $primary_bk ); + if ( false !== $last_time ) { + $information['primaryLasttimeBackup'] = $last_time; // to fix overwrite other last time primary backup. + } } $last_post = wp_get_recent_posts( array( 'numberposts' => absint( '1' ) ) ); diff --git a/class/class-mainwp-child.php b/class/class-mainwp-child.php index 47e6dbce..2076a0e4 100644 --- a/class/class-mainwp-child.php +++ b/class/class-mainwp-child.php @@ -33,7 +33,7 @@ class MainWP_Child { * * @var string MainWP Child plugin version. */ - public static $version = '4.6'; + public static $version = '5.0'; /** * Private variable containing the latest MainWP Child update version. @@ -96,8 +96,13 @@ public function __construct( $plugin_file ) { add_action( 'core_upgrade_preamble', array( MainWP_Child_Updates::get_instance(), 'detect_premium_themesplugins_updates' ) ); MainWP_Pages::get_instance()->init(); + + // Initiate MainWP Cache Control class. MainWP_Child_Cache_Purge::instance(); + // Initiate MainWP Child API Backups class. + MainWP_Child_Api_Backups::instance(); + if ( is_admin() ) { MainWP_Helper::update_option( 'mainwp_child_plugin_version', self::$version, 'yes' ); } diff --git a/class/class-mainwp-clone.php b/class/class-mainwp-clone.php index d524e340..9d60bc6d 100644 --- a/class/class-mainwp-clone.php +++ b/class/class-mainwp-clone.php @@ -215,7 +215,6 @@ public static function upload_mimes( $mime_types = array() ) { * @uses \MainWP\Child\MainWP_Connect::is_valid_auth() * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() * @uses \MainWP\Child\MainWP_Helper::write() - * @uses \MainWP\Child\MainWP_Utility::upload_file() */ public function request_clone_funct() { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated. // phpcs:disable WordPress.Security.NonceVerification @@ -234,7 +233,7 @@ public function request_clone_funct() { // phpcs:ignore -- Current complexity is if ( 'dl' === $cloneFunc ) { $f = isset( $_REQUEST['f'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['f'] ) ) : ''; if ( ! empty( $f ) ) { - MainWP_Utility::instance()->upload_file( sanitize_text_field( wp_unslash( $_REQUEST['f'] ) ) ); + MainWP_Utility::instance()->upload_file_backup( sanitize_text_field( wp_unslash( $_REQUEST['f'] ) ) ); } exit; } elseif ( 'deleteCloneBackup' === $cloneFunc ) { diff --git a/class/class-mainwp-connect.php b/class/class-mainwp-connect.php index 458b6c65..6c17db51 100644 --- a/class/class-mainwp-connect.php +++ b/class/class-mainwp-connect.php @@ -513,8 +513,6 @@ private function get_request_files() { * Handle redirects. * * @return bool Returns false if $_REQUEST['fdl'] is set. - * - * @uses \MainWP\Child\MainWP_Utility::upload_file() */ private function check_redirects() { // phpcs:disable WordPress.Security.NonceVerification @@ -526,17 +524,17 @@ private function check_redirects() { $foffset = isset( $_REQUEST['foffset'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['foffset'] ) ) : 0; - MainWP_Utility::instance()->upload_file( $fdl, $foffset ); + MainWP_Utility::instance()->upload_file_backup( $fdl, $foffset ); exit; } $open_location = ! empty( $_REQUEST['open_location'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['open_location'] ) ) : ''; // support for custom wp-admin slug. - if ( ! empty( $open_locatio ) ) { + if ( ! empty( $open_location ) ) { $this->open_location_redirect( $open_location ); } // phpcs:enable - $this->where_redirect(); + $this->where_authed_redirect(); } /** @@ -590,12 +588,12 @@ public static function parse_query( $val ) { } /** - * Method where_redirect() + * Method where_authed_redirect() * * Safe redirect to wanted location. */ - private function where_redirect() { - // phpcs:disable WordPress.Security.NonceVerification + private function where_authed_redirect() { + // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $where = isset( $_REQUEST['where'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['where'] ) ) : ''; if ( isset( $_POST['f'] ) || isset( $_POST['file'] ) ) { $file = ''; @@ -610,12 +608,69 @@ private function where_redirect() { } $_SESSION['file'] = $file; $_SESSION['size'] = isset( $_POST['size'] ) ? sanitize_text_field( wp_unslash( $_POST['size'] ) ) : ''; + } elseif ( isset( $_REQUEST['filedl'] ) && ! empty( $_REQUEST['filedl'] ) ) { + $auth_dl = array( + 'file' => sanitize_text_field( wp_unslash( $_REQUEST['filedl'] ) ), + 'dir' => isset( $_REQUEST['dirdl'] ) && ! empty( $_REQUEST['dirdl'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['dirdl'] ) ) : false, + ); + $auth_dl = apply_filters( 'mainwp_child_authed_download_params', $auth_dl ); + if ( ! empty( $auth_dl['file'] ) && isset( $auth_dl['dir'] ) ) { + $allow_dl = $this->validate_pre_download_file( $auth_dl['file'], $auth_dl['dir'] ); + if ( $allow_dl ) { + $downloading = MainWP_Utility::instance()->upload_file( $auth_dl['file'], $auth_dl['dir'] ); + if ( true === $downloading ) { + exit; + } + } + } } // phpcs:enable wp_safe_redirect( admin_url( $where ) ); exit(); } + /** + * Method validate_pre_download_file() + * + * @param string $file File param request. + * @param string $dir Directory param request. + * + * @return bool Valid or not valid to download file. + */ + public function validate_pre_download_file( $file, $dir ) { + + if ( empty( $dir ) ) { + $dir = dirname( $file ); // get dir of file to validate. + } + + if ( false === stripos( ABSPATH, $dir ) ) { + $parent_dir = dirname( $dir ); + if ( false === stripos( ABSPATH, $parent_dir ) ) { // check parent folder of download folder. + $parent_parent_dir = dirname( $parent_dir ); + if ( false === stripos( ABSPATH, $parent_parent_dir ) ) { // check parent parent folder of download folder. + return false; // only allows download in related home folder. + } + } + } + + if ( empty( $dir ) || '/' === $dir || '\\' === $dir || '.' === $dir || stristr( $dir, '..' ) ) { + return false; // not allow. + } + + $file = str_replace( $dir . '/', '', $file ); + + if ( stristr( $file, '/' ) ) { + return false; // not allow to secure. + } + + // file not found. + if ( ! file_exists( $dir . '/' . $file ) ) { + return false; + } + + return true; + } + /** * Method check_login() * @@ -628,7 +683,7 @@ private function where_redirect() { * @uses \MainWP\Child\MainWP_Helper::instance()->error() */ public function check_login() { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated. - // phpcs:disable WordPress.Security.NonceVerification + // phpcs:disable WordPress.Security.NonceVerification if ( ! isset( $_POST['mainwpsignature'] ) || empty( $_POST['mainwpsignature'] ) ) { return false; } @@ -696,7 +751,7 @@ public function check_login() { // phpcs:ignore -- Current complexity is the onl die(); } } - // phpcs:enable + // phpcs:enable } /** diff --git a/class/class-mainwp-custom-post-type.php b/class/class-mainwp-custom-post-type.php index 0cd9ce7e..4cfbbd23 100644 --- a/class/class-mainwp-custom-post-type.php +++ b/class/class-mainwp-custom-post-type.php @@ -104,14 +104,18 @@ public function action() { private function import_custom_post() { add_filter( 'http_request_host_is_external', '__return_true' ); - // phpcs:disable WordPress.Security.NonceVerification - if ( ! isset( $_POST['data'] ) || strlen( wp_unslash( $_POST['data'] ) ) < 2 ) { //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + + // phpcs:disable WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + if ( ! isset( $_POST['data'] ) || ( is_string( $_POST['data'] ) && strlen( wp_unslash( $_POST['data'] ) ) < 2 ) ) { return array( 'error' => esc_html__( 'Missing data', $this->plugin_translate ) ); } - - $data = isset( $_POST['data'] ) ? stripslashes( wp_unslash( $_POST['data'] ) ) : ''; //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized - - $data = json_decode( $data, true ); + $data = array(); + if ( is_string( $_POST['data'] ) ) { // to compatible. + $data = stripslashes( wp_unslash( $_POST['data'] ) ); + $data = json_decode( $data, true ); + } elseif ( is_array( $_POST['data'] ) ) { + $data = wp_unslash( $_POST['data'] ); + } if ( empty( $data ) || ! is_array( $data ) || ! isset( $data['post'] ) ) { return array( 'error' => esc_html__( 'Cannot decode data', $this->plugin_translate ) ); diff --git a/class/class-mainwp-security.php b/class/class-mainwp-security.php index ccf02109..b12b08e7 100644 --- a/class/class-mainwp-security.php +++ b/class/class-mainwp-security.php @@ -664,9 +664,11 @@ public static function wpcore_updated_ok() { include_once ABSPATH . '/wp-admin/includes/update.php'; $ok = true; $core_updates = get_core_updates(); - foreach ( $core_updates as $core => $update ) { - if ( 'upgrade' === $update->response ) { - $ok = false; + if ( is_array( $core_updates ) ) { + foreach ( $core_updates as $core => $update ) { + if ( 'upgrade' === $update->response ) { + $ok = false; + } } } return $ok; diff --git a/class/class-mainwp-utility.php b/class/class-mainwp-utility.php index c78e3380..9f693411 100644 --- a/class/class-mainwp-utility.php +++ b/class/class-mainwp-utility.php @@ -206,14 +206,46 @@ public static function cron_active() { * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() * @uses \MainWP\Child\MainWP_Helper::ends_with() */ - public function upload_file( $file, $offset = 0 ) { - + public function upload_file_backup( $file, $offset = 0 ) { if ( empty( $file ) || stristr( $file, '..' ) ) { return false; } - $dirs = MainWP_Helper::get_mainwp_dir( 'backup' ); $backupdir = $dirs[0]; + $this->upload_file( $file, $backupdir, $offset ); + } + + /** + * Method upload_file() + * + * Upload bacup fils to execute clone or restore proces. + * + * @param mixed $file Backup file. + * @param mixed|false $dir dir value. + * @param int $offset Offset value. + * + * @uses \MainWP\Child\MainWP_Helper::get_mainwp_dir() + * @uses \MainWP\Child\MainWP_Helper::ends_with() + */ + public function upload_file( $file, $dir = false, $offset = 0 ) { + + if ( empty( $file ) || stristr( $file, '..' ) ) { + return false; + } + + if ( empty( $dir ) ) { + $fullpath = $file; + } else { + $fullpath = $dir . $file; + } + + if ( false !== stripos( $fullpath, 'wp-config.php' ) ) { + return false; + } + + if ( ! file_exists( $fullpath ) ) { + return false; + } header( 'Content-Description: File Transfer' ); @@ -228,11 +260,12 @@ public function upload_file( $file, $offset = 0 ) { header( 'Expires: 0' ); header( 'Cache-Control: must-revalidate' ); header( 'Pragma: public' ); - header( 'Content-Length: ' . filesize( $backupdir . $file ) ); + header( 'Content-Length: ' . filesize( $fullpath ) ); while ( ob_get_level() ) { ob_end_clean(); } - $this->readfile_chunked( $backupdir . $file, $offset ); + $this->readfile_chunked( $fullpath, $offset ); + return true; } /** @@ -1047,7 +1080,7 @@ public static function get_lasttime_backup( $by ) { // phpcs:ignore -- required } if ( ! $activated ) { - return 0; + return false; } return get_option( 'mainwp_lasttime_backup_' . $by, 0 ); diff --git a/libs/phpseclib/composer.lock b/libs/phpseclib/composer.lock index 555fcd23..df3981ce 100644 --- a/libs/phpseclib/composer.lock +++ b/libs/phpseclib/composer.lock @@ -125,16 +125,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.20", + "version": "3.0.35", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67" + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67", - "reference": "543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4b1827beabce71953ca479485c0ae9c51287f2fe", + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe", "shasum": "" }, "require": { @@ -215,7 +215,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.20" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.35" }, "funding": [ { @@ -231,7 +231,7 @@ "type": "tidelift" } ], - "time": "2023-06-13T06:30:34+00:00" + "time": "2023-12-29T01:59:53+00:00" } ], "packages-dev": [], diff --git a/libs/phpseclib/vendor/autoload.php b/libs/phpseclib/vendor/autoload.php index 8f9af855..d7029f9c 100644 --- a/libs/phpseclib/vendor/autoload.php +++ b/libs/phpseclib/vendor/autoload.php @@ -3,10 +3,23 @@ // autoload.php @generated by Composer if (PHP_VERSION_ID < 50600) { - echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; - exit(1); + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, $err); + } elseif (!headers_sent()) { + echo $err; + } + } + trigger_error( + $err, + E_USER_ERROR + ); } require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit489abf9341e333fb55deb81103e35d6a::getLoader(); +return ComposerAutoloaderInit7e63f96d00138467a26a6593e1101678::getLoader(); diff --git a/libs/phpseclib/vendor/composer/ClassLoader.php b/libs/phpseclib/vendor/composer/ClassLoader.php index afef3fa2..7824d8f7 100644 --- a/libs/phpseclib/vendor/composer/ClassLoader.php +++ b/libs/phpseclib/vendor/composer/ClassLoader.php @@ -42,35 +42,37 @@ */ class ClassLoader { - /** @var ?string */ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ private $vendorDir; // PSR-4 /** - * @var array[] - * @psalm-var array> + * @var array> */ private $prefixLengthsPsr4 = array(); /** - * @var array[] - * @psalm-var array> + * @var array> */ private $prefixDirsPsr4 = array(); /** - * @var array[] - * @psalm-var array + * @var list */ private $fallbackDirsPsr4 = array(); // PSR-0 /** - * @var array[] - * @psalm-var array> + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> */ private $prefixesPsr0 = array(); /** - * @var array[] - * @psalm-var array + * @var list */ private $fallbackDirsPsr0 = array(); @@ -78,8 +80,7 @@ class ClassLoader private $useIncludePath = false; /** - * @var string[] - * @psalm-var array + * @var array */ private $classMap = array(); @@ -87,29 +88,29 @@ class ClassLoader private $classMapAuthoritative = false; /** - * @var bool[] - * @psalm-var array + * @var array */ private $missingClasses = array(); - /** @var ?string */ + /** @var string|null */ private $apcuPrefix; /** - * @var self[] + * @var array */ private static $registeredLoaders = array(); /** - * @param ?string $vendorDir + * @param string|null $vendorDir */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); } /** - * @return string[] + * @return array> */ public function getPrefixes() { @@ -121,8 +122,7 @@ public function getPrefixes() } /** - * @return array[] - * @psalm-return array> + * @return array> */ public function getPrefixesPsr4() { @@ -130,8 +130,7 @@ public function getPrefixesPsr4() } /** - * @return array[] - * @psalm-return array + * @return list */ public function getFallbackDirs() { @@ -139,8 +138,7 @@ public function getFallbackDirs() } /** - * @return array[] - * @psalm-return array + * @return list */ public function getFallbackDirsPsr4() { @@ -148,8 +146,7 @@ public function getFallbackDirsPsr4() } /** - * @return string[] Array of classname => path - * @psalm-return array + * @return array Array of classname => path */ public function getClassMap() { @@ -157,8 +154,7 @@ public function getClassMap() } /** - * @param string[] $classMap Class to filename map - * @psalm-param array $classMap + * @param array $classMap Class to filename map * * @return void */ @@ -175,24 +171,25 @@ public function addClassMap(array $classMap) * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories * * @return void */ public function add($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, - (array) $paths + $paths ); } @@ -201,19 +198,19 @@ public function add($prefix, $paths, $prepend = false) $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; + $this->prefixesPsr0[$first][$prefix] = $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], - (array) $paths + $paths ); } } @@ -222,9 +219,9 @@ public function add($prefix, $paths, $prepend = false) * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException * @@ -232,17 +229,18 @@ public function add($prefix, $paths, $prepend = false) */ public function addPsr4($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, - (array) $paths + $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { @@ -252,18 +250,18 @@ public function addPsr4($prefix, $paths, $prepend = false) throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; + $this->prefixDirsPsr4[$prefix] = $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], - (array) $paths + $paths ); } } @@ -272,8 +270,8 @@ public function addPsr4($prefix, $paths, $prepend = false) * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories * * @return void */ @@ -290,8 +288,8 @@ public function set($prefix, $paths) * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException * @@ -425,7 +423,8 @@ public function unregister() public function loadClass($class) { if ($file = $this->findFile($class)) { - includeFile($file); + $includeFile = self::$includeFile; + $includeFile($file); return true; } @@ -476,9 +475,9 @@ public function findFile($class) } /** - * Returns the currently registered loaders indexed by their corresponding vendor directories. + * Returns the currently registered loaders keyed by their corresponding vendor directories. * - * @return self[] + * @return array */ public static function getRegisteredLoaders() { @@ -555,18 +554,26 @@ private function findFileWithExtension($class, $ext) return false; } -} -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - * @private - */ -function includeFile($file) -{ - include $file; + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } } diff --git a/libs/phpseclib/vendor/composer/InstalledVersions.php b/libs/phpseclib/vendor/composer/InstalledVersions.php index 41bc143c..51e734a7 100644 --- a/libs/phpseclib/vendor/composer/InstalledVersions.php +++ b/libs/phpseclib/vendor/composer/InstalledVersions.php @@ -28,7 +28,7 @@ class InstalledVersions { /** * @var mixed[]|null - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null */ private static $installed; @@ -39,7 +39,7 @@ class InstalledVersions /** * @var array[] - * @psalm-var array}> + * @psalm-var array}> */ private static $installedByVendor = array(); @@ -98,7 +98,7 @@ public static function isInstalled($packageName, $includeDevRequirements = true) { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ public static function isInstalled($packageName, $includeDevRequirements = true) */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -243,7 +243,7 @@ public static function getInstallPath($packageName) /** * @return array - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} */ public static function getRootPackage() { @@ -257,7 +257,7 @@ public static function getRootPackage() * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} */ public static function getRawData() { @@ -280,7 +280,7 @@ public static function getRawData() * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ public static function getAllRawData() { @@ -303,7 +303,7 @@ public static function getAllRawData() * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data */ public static function reload($data) { @@ -313,7 +313,7 @@ public static function reload($data) /** * @return array[] - * @psalm-return list}> + * @psalm-return list}> */ private static function getInstalled() { @@ -328,7 +328,9 @@ private static function getInstalled() if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ private static function getInstalled() // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } diff --git a/libs/phpseclib/vendor/composer/autoload_real.php b/libs/phpseclib/vendor/composer/autoload_real.php index ee548ee6..cc194977 100644 --- a/libs/phpseclib/vendor/composer/autoload_real.php +++ b/libs/phpseclib/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit489abf9341e333fb55deb81103e35d6a +class ComposerAutoloaderInit7e63f96d00138467a26a6593e1101678 { private static $loader; @@ -24,34 +24,27 @@ public static function getLoader() require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit489abf9341e333fb55deb81103e35d6a', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit7e63f96d00138467a26a6593e1101678', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit489abf9341e333fb55deb81103e35d6a', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit7e63f96d00138467a26a6593e1101678', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit489abf9341e333fb55deb81103e35d6a::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit7e63f96d00138467a26a6593e1101678::getInitializer($loader)); $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInit489abf9341e333fb55deb81103e35d6a::$files; - foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire489abf9341e333fb55deb81103e35d6a($fileIdentifier, $file); + $filesToLoad = \Composer\Autoload\ComposerStaticInit7e63f96d00138467a26a6593e1101678::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); } return $loader; } } - -/** - * @param string $fileIdentifier - * @param string $file - * @return void - */ -function composerRequire489abf9341e333fb55deb81103e35d6a($fileIdentifier, $file) -{ - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - - require $file; - } -} diff --git a/libs/phpseclib/vendor/composer/autoload_static.php b/libs/phpseclib/vendor/composer/autoload_static.php index 85972184..71df5a44 100644 --- a/libs/phpseclib/vendor/composer/autoload_static.php +++ b/libs/phpseclib/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit489abf9341e333fb55deb81103e35d6a +class ComposerStaticInit7e63f96d00138467a26a6593e1101678 { public static $files = array ( 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', @@ -39,9 +39,9 @@ class ComposerStaticInit489abf9341e333fb55deb81103e35d6a public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit489abf9341e333fb55deb81103e35d6a::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit489abf9341e333fb55deb81103e35d6a::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit489abf9341e333fb55deb81103e35d6a::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit7e63f96d00138467a26a6593e1101678::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit7e63f96d00138467a26a6593e1101678::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit7e63f96d00138467a26a6593e1101678::$classMap; }, null, ClassLoader::class); } diff --git a/libs/phpseclib/vendor/composer/installed.json b/libs/phpseclib/vendor/composer/installed.json index 15845673..2c8ddfd6 100644 --- a/libs/phpseclib/vendor/composer/installed.json +++ b/libs/phpseclib/vendor/composer/installed.json @@ -125,17 +125,17 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.20", - "version_normalized": "3.0.20.0", + "version": "3.0.35", + "version_normalized": "3.0.35.0", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67" + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67", - "reference": "543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4b1827beabce71953ca479485c0ae9c51287f2fe", + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe", "shasum": "" }, "require": { @@ -153,7 +153,7 @@ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." }, - "time": "2023-06-13T06:30:34+00:00", + "time": "2023-12-29T01:59:53+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -218,7 +218,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.20" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.35" }, "funding": [ { diff --git a/libs/phpseclib/vendor/composer/installed.php b/libs/phpseclib/vendor/composer/installed.php index 6e3aaff8..de007ab3 100644 --- a/libs/phpseclib/vendor/composer/installed.php +++ b/libs/phpseclib/vendor/composer/installed.php @@ -1,49 +1,49 @@ array( + 'name' => '__root__', 'pretty_version' => '1.0.0+no-version-set', 'version' => '1.0.0.0', + 'reference' => NULL, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => NULL, - 'name' => '__root__', 'dev' => true, ), 'versions' => array( '__root__' => array( 'pretty_version' => '1.0.0+no-version-set', 'version' => '1.0.0.0', + 'reference' => NULL, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => NULL, 'dev_requirement' => false, ), 'paragonie/constant_time_encoding' => array( 'pretty_version' => 'v2.6.3', 'version' => '2.6.3.0', + 'reference' => '58c3f47f650c94ec05a151692652a868995d2938', 'type' => 'library', 'install_path' => __DIR__ . '/../paragonie/constant_time_encoding', 'aliases' => array(), - 'reference' => '58c3f47f650c94ec05a151692652a868995d2938', 'dev_requirement' => false, ), 'paragonie/random_compat' => array( 'pretty_version' => 'v9.99.100', 'version' => '9.99.100.0', + 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a', 'type' => 'library', 'install_path' => __DIR__ . '/../paragonie/random_compat', 'aliases' => array(), - 'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a', 'dev_requirement' => false, ), 'phpseclib/phpseclib' => array( - 'pretty_version' => '3.0.20', - 'version' => '3.0.20.0', + 'pretty_version' => '3.0.35', + 'version' => '3.0.35.0', + 'reference' => '4b1827beabce71953ca479485c0ae9c51287f2fe', 'type' => 'library', 'install_path' => __DIR__ . '/../phpseclib/phpseclib', 'aliases' => array(), - 'reference' => '543a1da81111a0bfd6ae7bbc2865c5e89ed3fc67', 'dev_requirement' => false, ), ), diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/README.md b/libs/phpseclib/vendor/phpseclib/phpseclib/README.md index 64c06ba2..98e57968 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/README.md +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/README.md @@ -51,8 +51,7 @@ SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 / * PHP4 compatible * Composer compatible (PSR-0 autoloading) * Install using Composer: `composer require phpseclib/phpseclib:~1.0` -* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm) -* [Download 1.0.20 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.20.zip/download) +* [Download 1.0.22 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.22.zip/download) ## Security contact information diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php index 407f0369..09eb5b1b 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php @@ -94,7 +94,7 @@ abstract class AsymmetricKey /** * @param string $type - * @return string + * @return array|string */ abstract public function toString($type, array $options = []); @@ -130,7 +130,7 @@ protected static function initialize_static_variables() * * @param string $key * @param string $password optional - * @return AsymmetricKey + * @return \phpseclib3\Crypt\Common\PublicKey|\phpseclib3\Crypt\Common\PrivateKey */ public static function load($key, $password = false) { @@ -382,7 +382,7 @@ public static function addFileFormat($fullname) $shortname = $meta->getShortName(); self::$plugins[static::ALGORITHM]['Keys'][strtolower($shortname)] = $fullname; if ($meta->hasConstant('IS_INVISIBLE')) { - self::$invisiblePlugins[static::ALGORITHM] = strtolower($name); + self::$invisiblePlugins[static::ALGORITHM][] = strtolower($shortname); } } } diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php index 4638a539..7aa55480 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php @@ -141,6 +141,7 @@ private static function getPBES1EncryptionObject($algo) break; case 'RC2': $cipher = new RC2('cbc'); + $cipher->setKeyLength(64); break; case '3-KeyTripleDES': $cipher = new TripleDES('cbc'); @@ -218,7 +219,7 @@ private static function getPBES2EncryptionObject($algo) { switch ($algo) { case 'desCBC': - $cipher = new TripleDES('cbc'); + $cipher = new DES('cbc'); break; case 'des-EDE3-CBC': $cipher = new TripleDES('cbc'); diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php index 31bb2e87..175508d4 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php @@ -668,6 +668,8 @@ protected static function initialize_static_variables() switch (true) { // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster case (PHP_OS & "\xDF\xDF\xDF") === 'WIN': + case !function_exists('php_uname'): + case !is_string(php_uname('m')): case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM': case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8: self::$use_reg_intval = true; diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/IEEE.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/IEEE.php new file mode 100644 index 00000000..69139da4 --- /dev/null +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/IEEE.php @@ -0,0 +1,66 @@ + + * @copyright 2016 Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +namespace phpseclib3\Crypt\EC\Formats\Signature; + +use phpseclib3\Math\BigInteger; + +/** + * ASN1 Signature Handler + * + * @author Jim Wigginton + */ +abstract class IEEE +{ + /** + * Loads a signature + * + * @param string $sig + * @return array + */ + public static function load($sig) + { + if (!is_string($sig)) { + return false; + } + + $len = strlen($sig); + if ($len & 1) { + return false; + } + + $r = new BigInteger(substr($sig, 0, $len >> 1), 256); + $s = new BigInteger(substr($sig, $len >> 1), 256); + + return compact('r', 's'); + } + + /** + * Returns a signature in the appropriate format + * + * @param \phpseclib3\Math\BigInteger $r + * @param \phpseclib3\Math\BigInteger $s + * @return string + */ + public static function save(BigInteger $r, BigInteger $s) + { + $r = $r->toBytes(); + $s = $s->toBytes(); + $len = max(strlen($r), strlen($s)); + return str_pad($r, $len, "\0", STR_PAD_LEFT) . str_pad($s, $len, "\0", STR_PAD_LEFT); + } +} diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php index 13571997..19dcfea3 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php @@ -332,6 +332,7 @@ public static function createKey($bits = 2048) openssl_pkey_export($rsa, $privatekeystr, null, $config); // clear the buffer of error strings stemming from a minimalistic openssl.cnf + // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up while (openssl_error_string() !== false) { } diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php index cd8b7627..ff31f9c8 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php @@ -833,7 +833,6 @@ protected function setupInlineCrypt() // Generating encrypt code: $init_encrypt .= ' - static $tables; if (empty($tables)) { $tables = &$this->getTables(); } @@ -890,7 +889,6 @@ protected function setupInlineCrypt() // Generating decrypt code: $init_decrypt .= ' - static $invtables; if (empty($invtables)) { $invtables = &$this->getInvTables(); } @@ -947,7 +945,7 @@ protected function setupInlineCrypt() $this->inline_crypt = $this->createInlineCryptFunction( [ - 'init_crypt' => '', + 'init_crypt' => 'static $tables; static $invtables;', 'init_encrypt' => $init_encrypt, 'init_decrypt' => $init_decrypt, 'encrypt_block' => $encrypt_block, diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php index 93fe6c95..3096ff1a 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php @@ -21,7 +21,6 @@ namespace phpseclib3\File; -use DateTime; use phpseclib3\Common\Functions\Strings; use phpseclib3\File\ASN1\Element; use phpseclib3\Math\BigInteger; @@ -1403,7 +1402,7 @@ public static function convert($in, $from = self::TYPE_UTF8_STRING, $to = self:: return false; } break; - case ($c & 0x80000000) != 0: + case ($c & (PHP_INT_SIZE == 8 ? 0x80000000 : (1 << 31))) != 0: return false; case $c >= 0x04000000: $v .= chr(0x80 | ($c & 0x3F)); diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/X509.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/X509.php index b9f1c79e..5e2f073f 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/X509.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/File/X509.php @@ -1042,7 +1042,8 @@ public function validateURL($url) if ($names = $this->getExtension('id-ce-subjectAltName')) { foreach ($names as $name) { foreach ($name as $key => $value) { - $value = str_replace(['.', '*'], ['\.', '[^.]*'], $value); + $value = preg_quote($value); + $value = str_replace('\*', '[^.]*', $value); switch ($key) { case 'dNSName': /* From RFC2818 "HTTP over TLS": diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php index 70491abd..67d4788f 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php @@ -100,10 +100,6 @@ public static function setEngine($main, array $modexps = ['DefaultEngine']) /** @var class-string $fqmain */ self::$mainEngine = $fqmain; - if (!in_array('Default', $modexps)) { - $modexps[] = 'DefaultEngine'; - } - $found = false; foreach ($modexps as $modexp) { try { @@ -140,18 +136,23 @@ private static function initialize_static_variables() { if (!isset(self::$mainEngine)) { $engines = [ - ['GMP'], + ['GMP', ['DefaultEngine']], ['PHP64', ['OpenSSL']], ['BCMath', ['OpenSSL']], - ['PHP32', ['OpenSSL']] + ['PHP32', ['OpenSSL']], + ['PHP64', ['DefaultEngine']], + ['PHP32', ['DefaultEngine']] ]; + foreach ($engines as $engine) { try { - self::setEngine($engine[0], isset($engine[1]) ? $engine[1] : []); - break; + self::setEngine($engine[0], $engine[1]); + return; } catch (\Exception $e) { } } + + throw new \UnexpectedValueException('No valid BigInteger found. This is only possible when JIT is enabled on Windows and neither the GMP or BCMath extensions are available so either disable JIT or install GMP / BCMath'); } } diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php index 2b00bc37..abdf3b47 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php @@ -644,6 +644,11 @@ protected function powModOuter(Engine $e, Engine $n) return $this->normalize($temp->powModInner($e, $n)); } + if ($this->compare($n) > 0) { + list(, $temp) = $this->divide($n); + return $temp->powModInner($e, $n); + } + return $this->powModInner($e, $n); } diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php index ab9bdc99..7e85783e 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php @@ -1326,4 +1326,19 @@ private function bitwise_small_split($split) return array_reverse($vals); } + + /** + * @return bool + */ + protected static function testJITOnWindows() + { + // see https://github.com/php/php-src/issues/11917 + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && function_exists('opcache_get_status') && PHP_VERSION_ID < 80213 && !defined('PHPSECLIB_ALLOW_JIT')) { + $status = opcache_get_status(); + if ($status && isset($status['jit']) && $status['jit']['enabled'] && $status['jit']['on']) { + return true; + } + } + return false; + } } diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php index 964cd170..3a775e7d 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php @@ -80,10 +80,10 @@ protected function initialize($base) } $step = count($vals) & 3; if ($step) { - $digit = floor($digit / pow(2, 2 * $step)); + $digit = (int) floor($digit / pow(2, 2 * $step)); } if ($step != 3) { - $digit &= static::MAX_DIGIT; + $digit = (int) fmod($digit, static::BASE_FULL); $i++; } $vals[] = $digit; @@ -102,7 +102,7 @@ protected function initialize($base) */ public static function isValidEngine() { - return PHP_INT_SIZE >= 4; + return PHP_INT_SIZE >= 4 && !self::testJITOnWindows(); } /** diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php index ca11c08d..70a2e173 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php @@ -103,7 +103,7 @@ protected function initialize($base) */ public static function isValidEngine() { - return PHP_INT_SIZE >= 8; + return PHP_INT_SIZE >= 8 && !self::testJITOnWindows(); } /** diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BinaryField.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BinaryField.php index 3e21a67a..5da8c937 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BinaryField.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/BinaryField.php @@ -48,6 +48,15 @@ class BinaryField extends FiniteField public function __construct(...$indices) { $m = array_shift($indices); + if ($m > 571) { + /* sect571r1 and sect571k1 are the largest binary curves that https://www.secg.org/sec2-v2.pdf defines + altho theoretically there may be legit reasons to use binary finite fields with larger degrees + imposing a limit on the maximum size is both reasonable and precedented. in particular, + http://tools.ietf.org/html/rfc4253#section-6.1 (The Secure Shell (SSH) Transport Layer Protocol) says + "implementations SHOULD check that the packet length is reasonable in order for the implementation to + avoid denial of service and/or buffer overflow attacks" */ + throw new \OutOfBoundsException('Degrees larger than 571 are not supported'); + } $val = str_repeat('0', $m) . '1'; foreach ($indices as $index) { $val[$index] = '1'; diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php index 748f9a49..1bd7aaf0 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php @@ -263,7 +263,7 @@ public function squareRoot() $r = $this->value->powMod($temp, static::$modulo[$this->instanceID]); while (!$t->equals($one)) { - for ($i == clone $one; $i->compare($m) < 0; $i = $i->add($one)) { + for ($i = clone $one; $i->compare($m) < 0; $i = $i->add($one)) { if ($t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) { break; } @@ -312,8 +312,11 @@ public function negate() */ public function toBytes() { - $length = static::$modulo[$this->instanceID]->getLengthInBytes(); - return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT); + if (isset(static::$modulo[$this->instanceID])) { + $length = static::$modulo[$this->instanceID]->getLengthInBytes(); + return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT); + } + return $this->value->toBytes(); } /** diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php index ea35f934..45f748df 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php @@ -2127,7 +2127,7 @@ public function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = - if ($start >= 0) { $offset = $start; - } elseif ($mode & self::RESUME) { + } elseif ($mode & (self::RESUME | self::RESUME_START)) { // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called $size = $this->stat($remote_file)['size']; $offset = $size !== false ? $size : 0; @@ -2199,6 +2199,9 @@ public function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = - if ($local_start >= 0) { fseek($fp, $local_start); $size -= $local_start; + } elseif ($mode & self::RESUME) { + fseek($fp, $offset); + $size -= $offset; } } elseif ($dataCallback) { $size = 0; @@ -2486,14 +2489,6 @@ public function get($remote_file, $local_file = false, $offset = 0, $length = -1 } } - if ($length > 0 && $length <= $offset - $start) { - if ($local_file === false) { - $content = substr($content, 0, $length); - } else { - ftruncate($fp, $length + $res_offset); - } - } - if ($fclose_check) { fclose($fp); @@ -3300,6 +3295,7 @@ protected function reset_connection($reason) $this->use_request_id = false; $this->pwd = false; $this->requestBuffer = []; + $this->partial_init = false; } /** diff --git a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php index 85768250..ac70af9c 100644 --- a/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php +++ b/libs/phpseclib/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php @@ -1102,6 +1102,16 @@ class SSH2 */ private $errorOnMultipleChannels; + /** + * Terrapin Countermeasure + * + * "During initial KEX, terminate the connection if any unexpected or out-of-sequence packet is received" + * -- https://github.com/openssh/openssh-portable/commit/1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5 + * + * @var int + */ + private $extra_packets; + /** * Default Constructor. * @@ -1122,6 +1132,7 @@ public function __construct($host, $port = 22, $timeout = 10) 4 => 'NET_SSH2_MSG_DEBUG', 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', + 7 => 'NET_SSH2_MSG_EXT_INFO', // RFC 8308 20 => 'NET_SSH2_MSG_KEXINIT', 21 => 'NET_SSH2_MSG_NEWKEYS', 30 => 'NET_SSH2_MSG_KEXDH_INIT', @@ -1280,6 +1291,32 @@ public function sendKEXINITLast() $this->send_kex_first = false; } + /** + * stream_select wrapper + * + * Quoting https://stackoverflow.com/a/14262151/569976, + * "The general approach to `EINTR` is to simply handle the error and retry the operation again" + * + * This wrapper does that loop + */ + private static function stream_select(&$read, &$write, &$except, $seconds, $microseconds = null) + { + $remaining = $seconds + $microseconds / 1000000; + $start = microtime(true); + while (true) { + $result = @stream_select($read, $write, $except, $seconds, $microseconds); + if ($result !== false) { + return $result; + } + $elapsed = microtime(true) - $start; + $seconds = (int) ($remaining - floor($elapsed)); + $microseconds = (int) (1000000 * ($remaining - $seconds)); + if ($elapsed >= $remaining) { + return false; + } + } + } + /** * Connect to an SSHv2 server * @@ -1344,7 +1381,7 @@ private function connect() $start = microtime(true); $sec = (int) floor($this->curTimeout); $usec = (int) (1000000 * ($this->curTimeout - $sec)); - if (@stream_select($read, $write, $except, $sec, $usec) === false) { + if (static::stream_select($read, $write, $except, $sec, $usec) === false) { throw new \RuntimeException('Connection timed out whilst receiving server identification string'); } $elapsed = microtime(true) - $start; @@ -1509,6 +1546,8 @@ private function key_exchange($kexinit_payload_server = false) $preferred['client_to_server']['comp'] : SSH2::getSupportedCompressionAlgorithms(); + $kex_algorithms = array_merge($kex_algorithms, ['ext-info-c', 'kex-strict-c-v00@openssh.com']); + // some SSH servers have buggy implementations of some of the above algorithms switch (true) { case $this->server_identifier == 'SSH-2.0-SSHD': @@ -1525,6 +1564,20 @@ private function key_exchange($kexinit_payload_server = false) ['hmac-sha1-96', 'hmac-md5-96'] )); } + break; + case substr($this->server_identifier, 0, 24) == 'SSH-2.0-TurboFTP_SERVER_': + if (!isset($preferred['server_to_client']['crypt'])) { + $s2c_encryption_algorithms = array_values(array_diff( + $s2c_encryption_algorithms, + ['aes128-gcm@openssh.com', 'aes256-gcm@openssh.com'] + )); + } + if (!isset($preferred['client_to_server']['crypt'])) { + $c2s_encryption_algorithms = array_values(array_diff( + $c2s_encryption_algorithms, + ['aes128-gcm@openssh.com', 'aes256-gcm@openssh.com'] + )); + } } $client_cookie = Random::string(16); @@ -1549,6 +1602,7 @@ private function key_exchange($kexinit_payload_server = false) if ($kexinit_payload_server === false) { $this->send_binary_packet($kexinit_payload_client); + $this->extra_packets = 0; $kexinit_payload_server = $this->get_binary_packet(); if ( @@ -1580,6 +1634,11 @@ private function key_exchange($kexinit_payload_server = false) $this->languages_server_to_client, $first_kex_packet_follows ) = Strings::unpackSSH2('L10C', $response); + if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) { + if ($this->session_id === false && $this->extra_packets) { + throw new \UnexpectedValueException('Possible Terrapin Attack detected'); + } + } $this->supported_private_key_algorithms = $this->server_host_key_algorithms; @@ -1838,6 +1897,10 @@ private function key_exchange($kexinit_payload_server = false) throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS'); } + if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) { + $this->get_seq_no = $this->send_seq_no = 0; + } + $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); $this->encrypt = self::encryption_algorithm_to_crypt_instance($encrypt); @@ -2150,7 +2213,9 @@ private static function bad_algorithm_candidate($algorithm) */ public function login($username, ...$args) { - $this->auth[] = func_get_args(); + if (!$this->retry_connect) { + $this->auth[] = func_get_args(); + } // try logging with 'none' as an authentication method first since that's what // PuTTY does @@ -2289,10 +2354,26 @@ private function login_helper($username, $password = null) return $this->login_helper($username, $password); } $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); - throw new ConnectionClosedException('Connection closed by server'); + throw $e; + } + + list($type) = Strings::unpackSSH2('C', $response); + + if ($type == NET_SSH2_MSG_EXT_INFO) { + list($nr_extensions) = Strings::unpackSSH2('N', $response); + for ($i = 0; $i < $nr_extensions; $i++) { + list($extension_name, $extension_value) = Strings::unpackSSH2('ss', $response); + if ($extension_name == 'server-sig-algs') { + $this->supported_private_key_algorithms = explode(',', $extension_value); + } + } + + $response = $this->get_binary_packet(); + list($type) = Strings::unpackSSH2('C', $response); } - list($type, $service) = Strings::unpackSSH2('Cs', $response); + list($service) = Strings::unpackSSH2('s', $response); + if ($type != NET_SSH2_MSG_SERVICE_ACCEPT || $service != 'ssh-userauth') { $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT'); @@ -2568,7 +2649,7 @@ private function privatekey_login($username, PrivateKey $privatekey) $privatekey = $privatekey->withPadding(RSA::SIGNATURE_PKCS1); $algos = ['rsa-sha2-256', 'rsa-sha2-512', 'ssh-rsa']; if (isset($this->preferred['hostkey'])) { - $algos = array_intersect($this->preferred['hostkey'], $algos); + $algos = array_intersect($algos, $this->preferred['hostkey']); } $algo = self::array_intersect_first($algos, $this->supported_private_key_algorithms); switch ($algo) { @@ -3264,7 +3345,7 @@ public function __destruct() */ public function isConnected() { - return (bool) ($this->bitmap & self::MASK_CONNECTED); + return ($this->bitmap & self::MASK_CONNECTED) && is_resource($this->fsock) && !feof($this->fsock); } /** @@ -3377,6 +3458,8 @@ protected function reset_connection($reason) $this->session_id = false; $this->retry_connect = true; $this->get_seq_no = $this->send_seq_no = 0; + $this->channel_status = []; + $this->channel_id_last_interactive = 0; } /** @@ -3399,9 +3482,9 @@ private function get_binary_packet($skip_channel_filter = false) if (!$this->curTimeout) { if ($this->keepAlive <= 0) { - @stream_select($read, $write, $except, null); + static::stream_select($read, $write, $except, null); } else { - if (!@stream_select($read, $write, $except, $this->keepAlive)) { + if (!static::stream_select($read, $write, $except, $this->keepAlive)) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0)); return $this->get_binary_packet(true); } @@ -3415,7 +3498,7 @@ private function get_binary_packet($skip_channel_filter = false) $start = microtime(true); if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) { - if (!@stream_select($read, $write, $except, $this->keepAlive)) { + if (!static::stream_select($read, $write, $except, $this->keepAlive)) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0)); $elapsed = microtime(true) - $start; $this->curTimeout -= $elapsed; @@ -3429,7 +3512,7 @@ private function get_binary_packet($skip_channel_filter = false) $usec = (int) (1000000 * ($this->curTimeout - $sec)); // this can return a "stream_select(): unable to select [4]: Interrupted system call" error - if (!@stream_select($read, $write, $except, $sec, $usec)) { + if (!static::stream_select($read, $write, $except, $sec, $usec)) { $this->is_timeout = true; return true; } @@ -3702,13 +3785,15 @@ private function filter($payload, $skip_channel_filter) case NET_SSH2_MSG_DISCONNECT: Strings::shift($payload, 1); list($reason_code, $message) = Strings::unpackSSH2('Ns', $payload); - $this->errors[] = 'SSH_MSG_DISCONNECT: ' . static::$disconnect_reasons[$reason_code] . "\r\n$message"; + $this->errors[] = 'SSH_MSG_DISCONNECT: ' . self::$disconnect_reasons[$reason_code] . "\r\n$message"; $this->bitmap = 0; return false; case NET_SSH2_MSG_IGNORE: + $this->extra_packets++; $payload = $this->get_binary_packet($skip_channel_filter); break; case NET_SSH2_MSG_DEBUG: + $this->extra_packets++; Strings::shift($payload, 2); // second byte is "always_display" list($message) = Strings::unpackSSH2('s', $payload); $this->errors[] = "SSH_MSG_DEBUG: $message"; @@ -3717,6 +3802,7 @@ private function filter($payload, $skip_channel_filter) case NET_SSH2_MSG_UNIMPLEMENTED: return false; case NET_SSH2_MSG_KEXINIT: + // this is here for key re-exchanges after the initial key exchange if ($this->session_id !== false) { if (!$this->key_exchange($payload)) { $this->bitmap = 0; diff --git a/mainwp-child.php b/mainwp-child.php index bc533c9d..854a8863 100644 --- a/mainwp-child.php +++ b/mainwp-child.php @@ -12,7 +12,7 @@ * Author: MainWP * Author URI: https://mainwp.com * Text Domain: mainwp-child - * Version: 4.6 + * Version: 5.0 * Requires at least: 5.4 * Requires PHP: 7.4 */ diff --git a/readme.txt b/readme.txt index 8957c200..5be945df 100644 --- a/readme.txt +++ b/readme.txt @@ -7,7 +7,7 @@ Plugin URI: https://mainwp.com Requires at least: 6.2 Tested up to: 6.4.2 Requires PHP: 7.4 -Stable tag: 4.6 +Stable tag: 5.0 License: GPLv3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -28,8 +28,6 @@ MainWP is the **perfect solution for** - Marketers - In fact, anyone who wants to manage multiple WordPress sites -[Try the Live Demo](https://mainwp.com/live-demo/) - == Here’s Why WordPress Managers Love MainWP! == 💰 Free Forever @@ -166,6 +164,10 @@ Yes, we have a quick FAQ with a lot more questions and answers [here](https://ma == Changelog == += 5.0 - 2-27-2024 = +* Added: Support for the new API Backups providers - cPanel and Plesk +* Updated: Updated the phpSecLib library to enhance security and performance. + = 4.6 - 1-3-2024 = * Refactored: Updated and optimized the plugin codebase to align with the latest WordPress coding standards, contributing to better compatibility and performance.