From 886ffe64c21e35b8013b214e6f289cdd20854b94 Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Sun, 7 Jan 2024 23:29:00 +0800 Subject: [PATCH] Generic WIP ; next is to check YahnisElsts\PluginUpdateChecker\v5p3\UpdateChecker->requestMetadata does not point to a valid metadata file. HTTP response code is 404 (expected: 200) --- inc/class-wp-packages-update-server.php | 11 ++ inc/class-wppus-cloud-storage-manager.php | 38 +++--- inc/class-wppus-data-manager.php | 4 +- inc/class-wppus-license-manager.php | 4 +- inc/class-wppus-license-server.php | 5 +- inc/class-wppus-license-update-server.php | 2 + inc/class-wppus-nonce.php | 4 +- inc/class-wppus-package-manager.php | 23 +--- inc/class-wppus-remote-sources-manager.php | 52 ++------ inc/class-wppus-update-api.php | 99 ++++++++++------ inc/class-wppus-update-server.php | 15 ++- inc/class-wppus-webhook-api.php | 4 +- inc/templates/admin/packages-table-row.php | 4 +- inc/templates/admin/plugin-licenses-page.php | 1 + .../admin/plugin-remote-sources-page.php | 29 +---- integration/docs/generic.md | 5 +- .../Proxuc/Autoloader.php | 10 +- lib/proxy-update-checker/Proxuc/Factory.php | 2 +- .../Proxuc/Generic/Package.php | 29 +++++ .../Proxuc/Generic/Update.php | 53 +++++++++ .../Proxuc/Generic/UpdateChecker.php | 111 ++++++++++++++++++ .../Proxuc/Vcs/GenericUpdateChecker.php | 103 ++++++++++++++++ .../proxy-update-checker.php | 2 + .../includes/Wpupe/ZipMetadataParser.php | 25 +++- .../extension-meta/extension-meta.php | 21 +++- 25 files changed, 493 insertions(+), 163 deletions(-) create mode 100644 lib/proxy-update-checker/Proxuc/Generic/Package.php create mode 100644 lib/proxy-update-checker/Proxuc/Generic/Update.php create mode 100644 lib/proxy-update-checker/Proxuc/Generic/UpdateChecker.php create mode 100644 lib/proxy-update-checker/Proxuc/Vcs/GenericUpdateChecker.php diff --git a/inc/class-wp-packages-update-server.php b/inc/class-wp-packages-update-server.php index a9ff119..a376419 100644 --- a/inc/class-wp-packages-update-server.php +++ b/inc/class-wp-packages-update-server.php @@ -19,6 +19,7 @@ public function __construct( $init_hooks = false ) { add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ), 10, 1 ); add_action( 'admin_menu', array( $this, 'admin_menu' ), 5, 0 ); add_action( 'admin_menu', array( $this, 'admin_menu_help' ), 99, 0 ); + add_action( 'action_scheduler_failed_execution', array( $this, 'action_scheduler_failed_execution' ), 10, 3 ); add_filter( 'wppus_admin_scripts', array( $this, 'wppus_admin_scripts' ), 10, 1 ); add_filter( 'wppus_admin_styles', array( $this, 'wppus_admin_styles' ), 10, 1 ); @@ -36,6 +37,16 @@ public function __construct( $init_hooks = false ) { * Public methods *******************************************************************/ + public function action_scheduler_failed_execution( $action_id, Exception $exception, $context = '' ) { + php_log( + array( + 'action_id' => $action_id, + 'exception' => $exception, + 'context' => $context, + ) + ); + } + // WordPress hooks --------------------------------------------- public static function activate() { diff --git a/inc/class-wppus-cloud-storage-manager.php b/inc/class-wppus-cloud-storage-manager.php index 4ec3d41..edf525c 100644 --- a/inc/class-wppus-cloud-storage-manager.php +++ b/inc/class-wppus-cloud-storage-manager.php @@ -115,9 +115,10 @@ public function wppus_submitted_package_config( $config ) { $config, array( 'wppus_use_cloud_storage' => array( - 'value' => filter_input( INPUT_POST, 'wppus_use_cloud_storage', FILTER_VALIDATE_BOOLEAN ), - 'display_name' => __( 'Use Cloud Storage', 'wppus' ), - 'condition' => 'boolean', + 'value' => filter_input( INPUT_POST, 'wppus_use_cloud_storage', FILTER_VALIDATE_BOOLEAN ), + 'display_name' => __( 'Use Cloud Storage', 'wppus' ), + 'failure_display_message' => __( 'Something went wrong', 'wppus' ), + 'condition' => 'boolean', ), 'wppus_cloud_storage_access_key' => array( 'value' => filter_input( INPUT_POST, 'wppus_cloud_storage_access_key', FILTER_SANITIZE_FULL_SPECIAL_CHARS ), @@ -157,8 +158,6 @@ public function wppus_submitted_package_config( $config ) { public function wppus_package_option_update( $condition, $option_name, $option_info, $options ) { - php_log(); - if ( 'use-cloud-storage' === $option_info['condition'] ) { if ( @@ -182,6 +181,8 @@ public function wppus_package_option_update( $condition, $option_name, $option_i if ( ! $condition ) { update_option( 'wppus_use_cloud_storage', false ); } + } else { + $condition = true; } return $condition; @@ -430,7 +431,7 @@ public function wppus_check_remote_package_update_local_meta( $local_meta, $loca $wp_filesystem->is_file( $filename ) && $wp_filesystem->is_readable( $filename ) ) { - $local_meta = WshWordPressPackageParser::parsePackage( $filename, true ); + $local_meta = WshWordPressPackageParser_Extended::parsePackage( $filename, true ); } } catch ( PhpS3Exception $e ) { php_log( $e ); @@ -741,13 +742,24 @@ public function wppus_package_info( $package_info, $slug ) { ); if ( $result ) { - $package = Wpup_Package_Extended::fromArchive( $filename, $slug, $cache ); - $cache_value = $package->getMetadata(); + $package = false; - $cache->set( $cache_key, $cache_value, Wpup_ZipMetadataParser::$cacheTime ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + try { + $package = Wpup_Package_Extended::fromArchive( $filename, $slug, $cache ); + } catch ( Wpup_InvalidPackageException $e ) { + php_log( $e ); + + $cleanup = true; + } if ( $package ) { - $package_info = $cache_value; + $package_info = $package->getMetadata(); + + $cache->set( + $cache_key, + $package_info, + Wpup_ZipMetadataParser::$cacheTime // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + ); } } } else { @@ -756,10 +768,8 @@ public function wppus_package_info( $package_info, $slug ) { if ( $package_info ) { - if ( $package_info['details_url'] ) { - $package_info['type'] = 'theme'; - } else { - $package_info['type'] = 'plugin'; + if ( ! isset( $package_info['type'] ) ) { + $package_info['type'] = 'unknown'; } $package_info['file_name'] = $package_info['slug'] . '.zip'; diff --git a/inc/class-wppus-data-manager.php b/inc/class-wppus-data-manager.php index b298a3d..7e82f97 100644 --- a/inc/class-wppus-data-manager.php +++ b/inc/class-wppus-data-manager.php @@ -24,7 +24,7 @@ class WPPUS_Data_Manager { public function __construct( $init_hooks = false ) { if ( $init_hooks ) { - add_action( 'init', array( $this, 'init' ), 10, 0 ); + add_action( 'action_scheduler_init', array( $this, 'action_scheduler_init' ), 10, 0 ); } } @@ -34,7 +34,7 @@ public function __construct( $init_hooks = false ) { // WordPress hooks --------------------------------------------- - public function init() { + public function action_scheduler_init() { self::register_cleanup_events(); self::register_cleanup_schedules(); } diff --git a/inc/class-wppus-license-manager.php b/inc/class-wppus-license-manager.php index 86552bb..c0c87db 100644 --- a/inc/class-wppus-license-manager.php +++ b/inc/class-wppus-license-manager.php @@ -19,7 +19,7 @@ public function __construct( $init_hooks = false ) { if ( $use_licenses ) { $this->license_server = new WPPUS_License_Server(); - add_action( 'init', array( $this, 'init' ), 10, 0 ); + add_action( 'action_scheduler_init', array( $this, 'action_scheduler_init' ), 10, 0 ); add_action( 'wppus_packages_table_cell', array( $this, 'wppus_packages_table_cell' ), 10, 4 ); add_filter( 'wppus_packages_table_columns', array( $this, 'wppus_packages_table_columns' ), 10, 1 ); @@ -102,7 +102,7 @@ public static function deactivate() { do_action( 'wppus_cleared_license_schedule' ); } - public function init() { + public function action_scheduler_init() { $hook = 'wppus_expire_licenses'; if ( ! as_has_scheduled_action( $hook ) ) { diff --git a/inc/class-wppus-license-server.php b/inc/class-wppus-license-server.php index 68360e7..288c6ca 100644 --- a/inc/class-wppus-license-server.php +++ b/inc/class-wppus-license-server.php @@ -775,9 +775,10 @@ protected function validate_license_payload( $license, $partial = false ) { if ( ! ( $partial && ! isset( $license['package_type'] ) ) && 'plugin' !== $license['package_type'] && - 'theme' !== $license['package_type'] + 'theme' !== $license['package_type'] && + 'generic' !== $license['package_type'] ) { - $errors['invalid_package_type'] = __( 'The package type is required and must be "plugin" or "theme".', 'wppus' ); + $errors['invalid_package_type'] = __( 'The package type is required and must be "generic", "plugin" or "theme".', 'wppus' ); } if ( diff --git a/inc/class-wppus-license-update-server.php b/inc/class-wppus-license-update-server.php index e341b38..9aa0ff2 100644 --- a/inc/class-wppus-license-update-server.php +++ b/inc/class-wppus-license-update-server.php @@ -180,6 +180,8 @@ protected function verify_license_exists( $license_key ) { $result->product_ref = $result->package_slug . '/functions.php'; } elseif ( 'plugin' === $result->package_type ) { $result->product_ref = $result->package_slug . '/' . $result->package_slug . '.php'; + } elseif ( 'generic' === $result->package_type ) { + $result->product_ref = $result->package_slug . '/wppus.json'; } } diff --git a/inc/class-wppus-nonce.php b/inc/class-wppus-nonce.php index e1ff7c1..69e4e36 100644 --- a/inc/class-wppus-nonce.php +++ b/inc/class-wppus-nonce.php @@ -38,7 +38,7 @@ public static function deactivate() { public static function uninstall() {} - public static function wp() { + public static function action_scheduler_init() { $d = new DateTime( 'now', new DateTimeZone( wp_timezone_string() ) ); if ( ! as_has_scheduled_action( 'wppus_nonce_cleanup' ) ) { @@ -172,7 +172,7 @@ public static function register() { if ( ! self::is_doing_api_request() ) { add_action( 'init', array( get_class(), 'add_endpoints' ), 10, 0 ); - add_action( 'wp', array( get_class(), 'wp' ) ); + add_action( 'action_scheduler_init', array( get_class(), 'action_scheduler_init' ) ); add_action( 'wppus_nonce_cleanup', array( get_class(), 'wppus_nonce_cleanup' ) ); } diff --git a/inc/class-wppus-package-manager.php b/inc/class-wppus-package-manager.php index 61bda87..2a0c729 100644 --- a/inc/class-wppus-package-manager.php +++ b/inc/class-wppus-package-manager.php @@ -165,13 +165,7 @@ public function prime_package_from_remote() { Wppus_Update_Server::unlock_update_from_remote( $slug ); $api = WPPUS_Update_API::get_instance(); - $result = $api->download_remote_package( $slug, 'Theme', true ); - - if ( ! $result ) { - Wppus_Update_Server::unlock_update_from_remote( $slug ); - - $result = $api->download_remote_package( $slug, 'Plugin', true ); - } + $result = $api->download_remote_package( $slug, null, true ); } else { $error = new WP_Error( __METHOD__, @@ -580,10 +574,8 @@ public function get_package_info( $slug ) { if ( $package ) { $package_info = $package->getMetadata(); - if ( isset( $package_info['details_url'] ) ) { - $package_info['type'] = 'theme'; - } else { - $package_info['type'] = 'plugin'; + if ( ! isset( $package_info['type'] ) ) { + $package_info['type'] = 'unknown'; } $package_info['file_name'] = $package_info['slug'] . '.zip'; @@ -658,14 +650,7 @@ public function get_batch_package_info( $search = false ) { ); if ( $include ) { - $packages[ $meta['slug'] ] = $meta; - - if ( isset( $meta['details_url'] ) ) { - $packages[ $meta['slug'] ]['type'] = 'theme'; - } else { - $packages[ $meta['slug'] ]['type'] = 'plugin'; - } - + $packages[ $meta['slug'] ] = $meta; $packages[ $meta['slug'] ]['file_name'] = $meta['slug'] . '.zip'; $packages[ $meta['slug'] ]['file_size'] = $package->getFileSize(); $packages[ $meta['slug'] ]['file_last_modified'] = $package->getLastModified(); diff --git a/inc/class-wppus-remote-sources-manager.php b/inc/class-wppus-remote-sources-manager.php index 0137e5e..77e1239 100644 --- a/inc/class-wppus-remote-sources-manager.php +++ b/inc/class-wppus-remote-sources-manager.php @@ -11,13 +11,12 @@ public function __construct( $init_hooks = false ) { if ( $init_hooks ) { if ( get_option( 'wppus_use_remote_repository' ) ) { - add_action( 'init', array( $this, 'register_remote_check_scheduled_hooks' ), 10, 0 ); + add_action( 'action_scheduler_init', array( $this, 'register_remote_check_scheduled_hooks' ), 10, 0 ); } else { add_action( 'init', array( $this, 'clear_remote_check_scheduled_hooks' ), 10, 0 ); } add_action( 'wp_ajax_wppus_force_clean', array( $this, 'force_clean' ), 10, 0 ); - add_action( 'wp_ajax_wppus_force_register', array( $this, 'force_register' ), 10, 0 ); add_action( 'wp_ajax_wppus_remote_repository_test', array( $this, 'remote_repository_test' ), 10, 0 ); add_action( 'admin_menu', array( $this, 'admin_menu' ), 15, 0 ); add_filter( 'wppus_admin_tab_links', array( $this, 'wppus_admin_tab_links' ), 15, 1 ); @@ -104,37 +103,6 @@ public function wppus_admin_tab_states( $states, $page ) { return $states; } - public function force_register() { - $result = false; - $type = false; - - if ( isset( $_REQUEST['nonce'] ) && wp_verify_nonce( $_REQUEST['nonce'], 'wppus_plugin_options' ) ) { - $type = filter_input( INPUT_POST, 'type', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); - - if ( 'schedules' === $type ) { - $result = self::register_schedules(); - } - } - - if ( $result && $type ) { - wp_send_json_success(); - } elseif ( 'schedules' === $type ) { - $error = new WP_Error( - __METHOD__, - __( 'Error - check the packages directory is readable and not empty', 'wppus' ) - ); - - wp_send_json_error( $error ); - } else { - $error = new WP_Error( - __METHOD__, - __( 'Error - an unknown error has occured', 'wppus' ) . ': type = "' . $type . '" ; result = "' . $result . '"' - ); - - wp_send_json_error( $error ); - } - } - public function force_clean() { $result = false; $type = false; @@ -144,6 +112,12 @@ public function force_clean() { if ( 'schedules' === $type ) { $result = $this->clear_remote_check_scheduled_hooks(); + + if ( $result ) { + $this->reschedule_remote_check_recurring_events( + get_option( 'wppus_remote_repository_check_frequency', 'daily' ) + ); + } } } @@ -284,18 +258,6 @@ public static function clear_schedules() { return $manager->clear_remote_check_scheduled_hooks(); } - public static function register_schedules() { - $manager = new self(); - $result = false; - - if ( apply_filters( 'wppus_use_recurring_schedule', true ) ) { - $frequency = get_option( 'wppus_remote_repository_check_frequency', 'daily' ); - $result = $manager->reschedule_remote_check_recurring_events( $frequency ); - } - - return $result; - } - public function reschedule_remote_check_recurring_events( $frequency ) { if ( WPPUS_Update_API::is_doing_api_request() ) { diff --git a/inc/class-wppus-update-api.php b/inc/class-wppus-update-api.php index af85643..9c29132 100644 --- a/inc/class-wppus-update-api.php +++ b/inc/class-wppus-update-api.php @@ -22,6 +22,7 @@ public function __construct( $init_hooks = false ) { add_action( 'parse_request', array( $this, 'parse_request' ), -99, 0 ); add_action( 'wppus_checked_remote_package_update', array( $this, 'wppus_checked_remote_package_update' ), 10, 3 ); add_action( 'wppus_removed_package', array( $this, 'wppus_removed_package' ), 10, 3 ); + add_action( 'wppus_primed_package_from_remote', array( $this, 'wppus_primed_package_from_remote' ), 10, 2 ); add_filter( 'query_vars', array( $this, 'query_vars' ), -99, 1 ); } @@ -61,33 +62,13 @@ public function query_vars( $query_vars ) { } public function wppus_checked_remote_package_update( $needs_update, $type, $slug ) { - $config = self::get_config(); - - if ( - apply_filters( 'wppus_use_recurring_schedule', true ) && - $config['use_remote_repository'] && - $config['repository_service_url'] - ) { - $hook = 'wppus_check_remote_' . $slug; - $params = array( $slug, null, false ); + $this->schedule_check_remote_event( $slug ); + } - if ( ! as_has_scheduled_action( $hook, $params ) ) { - $frequency = apply_filters( - 'wppus_check_remote_frequency', - $config['repository_check_frequency'], - $slug - ); - $timestamp = time(); - $schedules = wp_get_schedules(); - $result = as_schedule_recurring_action( - $timestamp, - $schedules[ $frequency ]['interval'], - $hook, - $params - ); + public function wppus_primed_package_from_remote( $result, $slug ) { - do_action( 'wppus_scheduled_check_remote_event', $result, $slug, $timestamp, $frequency, $hook, $params ); - } + if ( $result ) { + $this->schedule_check_remote_event( $slug ); } } @@ -165,9 +146,23 @@ public function check_remote_update( $slug, $type ) { return $this->update_server->check_remote_package_update( $slug ); } - public function download_remote_package( $slug, $type, $force = false ) { + public function download_remote_package( $slug, $type = null, $force = false ) { $result = false; + if ( ! $type ) { + $types = array( 'Plugin', 'Theme', 'Generic' ); + + foreach ( $types as $type ) { + $result = $this->download_remote_package( $slug, $type, $force ); + + if ( $result ) { + break; + } + } + + return $result; + } + $this->init_server( $slug ); $this->update_server->set_type( $type ); @@ -182,6 +177,37 @@ public function download_remote_package( $slug, $type, $force = false ) { * Protected methods *******************************************************************/ + protected function schedule_check_remote_event( $slug ) { + $config = self::get_config(); + + if ( + apply_filters( 'wppus_use_recurring_schedule', true ) && + $config['use_remote_repository'] && + $config['repository_service_url'] + ) { + $hook = 'wppus_check_remote_' . $slug; + $params = array( $slug, null, false ); + + if ( ! as_has_scheduled_action( $hook, $params ) ) { + $frequency = apply_filters( + 'wppus_check_remote_frequency', + $config['repository_check_frequency'], + $slug + ); + $timestamp = time(); + $schedules = wp_get_schedules(); + $result = as_schedule_recurring_action( + $timestamp, + $schedules[ $frequency ]['interval'], + $hook, + $params + ); + + do_action( 'wppus_scheduled_check_remote_event', $result, $slug, $timestamp, $frequency, $hook, $params ); + } + } + } + protected function handle_api_request() { global $wp; @@ -215,15 +241,18 @@ protected function init_server( $package_id ) { $config ); - $this->update_server = new $server_class_name( - $config['use_remote_repository'], - home_url( '/wppus-update-api/' ), - $config['server_directory'], - $config['repository_service_url'], - $config['repository_branch'], - $config['repository_credentials'], - $config['repository_service_self_hosted'], - ); + if ( ! isset( $this->update_server ) || ! is_a( $this->update_server, $server_class_name ) ) { + $this->update_server = new $server_class_name( + $config['use_remote_repository'], + home_url( '/wppus-update-api/' ), + $config['server_directory'], + $config['repository_service_url'], + $config['repository_branch'], + $config['repository_credentials'], + $config['repository_service_self_hosted'], + ); + } + $this->update_server = apply_filters( 'wppus_update_server', $this->update_server, diff --git a/inc/class-wppus-update-server.php b/inc/class-wppus-update-server.php index 770f3b6..0e9ec5f 100644 --- a/inc/class-wppus-update-server.php +++ b/inc/class-wppus-update-server.php @@ -128,7 +128,7 @@ public function save_remote_package_to_local( $safe_slug ) { public function set_type( $type ) { $type = $type ? ucfirst( $type ) : false; - if ( 'Plugin' === $type || 'Theme' === $type ) { + if ( 'Plugin' === $type || 'Theme' === $type || 'Generic' === $type ) { $this->type = $type; } } @@ -141,7 +141,7 @@ public function check_remote_package_update( $slug ) { if ( $local_package instanceof Wpup_Package ) { $package_path = $local_package->getFileName(); - $local_meta = WshWordPressPackageParser::parsePackage( $package_path, true ); + $local_meta = WshWordPressPackageParser_Extended::parsePackage( $package_path, true ); $local_meta = apply_filters( 'wppus_check_remote_package_update_local_meta', $local_meta, @@ -169,7 +169,7 @@ public function check_remote_package_update( $slug ) { $this->type = ucfirst( $local_info['type'] ); - if ( 'Plugin' === $this->type || 'Theme' === $this->type ) { + if ( 'Plugin' === $this->type || 'Theme' === $this->type || 'Generic' === $this->type ) { $this->init_update_checker( $slug ); $remote_info = $this->update_checker->requestInfo(); @@ -209,7 +209,7 @@ public function remove_package( $slug ) { . filemtime( $package_path ) ); - $parsed_info = WshWordPressPackageParser::parsePackage( $package_path, true ); + $parsed_info = WshWordPressPackageParser_Extended::parsePackage( $package_path, true ); $type = ucfirst( $parsed_info['type'] ); $result = $wp_filesystem->delete( $package_path ); } @@ -385,6 +385,13 @@ protected function init_update_checker( $slug ) { $slug, $this->packageDirectory // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase ); + } elseif ( 'Generic' === $this->type ) { + $this->update_checker = new Proxuc_Vcs_GenericUpdateChecker( + new GitLabApi( trailingslashit( $this->repository_service_url ) . $slug ), + $slug, + $slug, + $this->packageDirectory // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + ); } } else { $this->update_checker = Proxuc_Factory::buildUpdateChecker( diff --git a/inc/class-wppus-webhook-api.php b/inc/class-wppus-webhook-api.php index 179c1d3..cfa146d 100644 --- a/inc/class-wppus-webhook-api.php +++ b/inc/class-wppus-webhook-api.php @@ -367,9 +367,7 @@ protected function handle_api_request() { do_action( 'wppus_scheduled_check_remote_event', $result, $package_id, $timestamp, false, $hook, $params ); } } else { - $api = WPPUS_Update_API::get_instance(); - - $api->download_remote_package( $package_id, $type ); + WPPUS_Update_API::get_instance()->download_remote_package( $package_id, $type ); } do_action( diff --git a/inc/templates/admin/packages-table-row.php b/inc/templates/admin/packages-table-row.php index d961fad..1882857 100644 --- a/inc/templates/admin/packages-table-row.php +++ b/inc/templates/admin/packages-table-row.php @@ -54,8 +54,10 @@ - + + + diff --git a/inc/templates/admin/plugin-licenses-page.php b/inc/templates/admin/plugin-licenses-page.php index e1f8d93..1ede57e 100644 --- a/inc/templates/admin/plugin-licenses-page.php +++ b/inc/templates/admin/plugin-licenses-page.php @@ -31,6 +31,7 @@ diff --git a/inc/templates/admin/plugin-remote-sources-page.php b/inc/templates/admin/plugin-remote-sources-page.php index d538e03..ce2beee 100644 --- a/inc/templates/admin/plugin-remote-sources-page.php +++ b/inc/templates/admin/plugin-remote-sources-page.php @@ -154,35 +154,18 @@ - - - - diff --git a/integration/docs/generic.md b/integration/docs/generic.md index 6d272a9..5ce35f5 100644 --- a/integration/docs/generic.md +++ b/integration/docs/generic.md @@ -87,10 +87,9 @@ HTTP/1.1 200 OK "author": "Alexandre Froger", "author_homepage": "https:\/\/dev.tld", "description": "Empty Generic Package", - "details_url": "https:\/\/dev.tld\/dummy-generic-package-details.md", "last_updated": "2024-01-01 00:00:00", "slug": "dummy-generic-package", - "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package, + "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package", "request_time_elapsed": "0.386" } @@ -109,7 +108,6 @@ HTTP/1.1 200 OK "author": "Alexandre Froger", "author_homepage": "https:\/\/dev.tld", "description": "Empty Generic Package", - "details_url": "https:\/\/dev.tld\/dummy-generic-package-details.md", "last_updated": "2024-01-01 00:00:00", "slug": "dummy-generic-package", "license_error": {}, @@ -128,7 +126,6 @@ In case a valid license key is provided: "author": "Alexandre Froger", "author_homepage": "https:\/\/dev.tld", "description": "Empty Generic Package", - "details_url": "https:\/\/dev.tld\/dummy-generic-package-details.md", "last_updated": "2024-01-01 00:00:00", "slug": "dummy-generic-package", "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D", diff --git a/lib/proxy-update-checker/Proxuc/Autoloader.php b/lib/proxy-update-checker/Proxuc/Autoloader.php index a7632cf..0707622 100644 --- a/lib/proxy-update-checker/Proxuc/Autoloader.php +++ b/lib/proxy-update-checker/Proxuc/Autoloader.php @@ -16,7 +16,15 @@ public function __construct() { public function autoload($className) { - if (strpos($className, $this->prefix) === 0) { //To know that the prefix is at the start of the classname + if ( strpos($className, 'Anyape\\' ) === 0 ) { + $class_parts = explode('\\', $className); + $path = $this->rootDir . 'Generic/' . end($class_parts) . '.php'; + + if (file_exists($path)) { + /** @noinspection PhpIncludeInspection */ + include $path; + } + } elseif (strpos($className, $this->prefix) === 0) { //To know that the prefix is at the start of the classname $path = substr($className, strlen($this->prefix)); $path = str_replace('_', '/', $path); $path = $this->rootDir . $path . '.php'; diff --git a/lib/proxy-update-checker/Proxuc/Factory.php b/lib/proxy-update-checker/Proxuc/Factory.php index 176d148..ecf66f2 100644 --- a/lib/proxy-update-checker/Proxuc/Factory.php +++ b/lib/proxy-update-checker/Proxuc/Factory.php @@ -44,7 +44,7 @@ class Proxuc_Factory { public static function buildUpdateChecker($metadataUrl, $slug, $plugin_file_name, $type, $package_container, $optionName = '') { //Plugin or theme? - if ($type !== 'Plugin' && $type !== 'Theme') { + if ($type !== 'Plugin' && $type !== 'Theme' && $type !== 'Generic') { return false; } diff --git a/lib/proxy-update-checker/Proxuc/Generic/Package.php b/lib/proxy-update-checker/Proxuc/Generic/Package.php new file mode 100644 index 0000000..ea8e073 --- /dev/null +++ b/lib/proxy-update-checker/Proxuc/Generic/Package.php @@ -0,0 +1,29 @@ +copyFields($object, $update); + + return $update; + } + + protected function validateMetadata($apiResponse) { + php_log(); + $required = array('version', 'package_data'); + + foreach ($required as $key) { + + if (!isset($apiResponse->$key) || empty($apiResponse->$key)) { + return new \WP_Error( + 'tuc-invalid-metadata', + sprintf('The generic metadata is missing the required "%s" key.', $key) + ); + } + } + return true; + } + + protected function getPrefixedFilter($tag) { + php_log(); + return parent::getPrefixedFilter($tag) . '_generic'; + } + } + +endif; diff --git a/lib/proxy-update-checker/Proxuc/Generic/UpdateChecker.php b/lib/proxy-update-checker/Proxuc/Generic/UpdateChecker.php new file mode 100644 index 0000000..84fc7ab --- /dev/null +++ b/lib/proxy-update-checker/Proxuc/Generic/UpdateChecker.php @@ -0,0 +1,111 @@ +debugMode = (bool)(constant('WP_DEBUG')); + $this->metadataUrl = $metadataUrl; + $this->directoryName = $directoryName; + $this->slug = !empty($slug) ? $slug : $this->directoryName; + $this->optionName = $optionName; + + if ( empty($this->optionName) ) { + + if ( $this->filterSuffix === '' ) { + $this->optionName = 'external_updates-' . $this->slug; + } else { + $this->optionName = $this->getUniqueName('external_updates'); + } + } + } + + /** + * For generics, the update array is indexed by generic directory name. + * + * @return string + */ + protected function getUpdateListKey() { + php_log(); + return $this->directoryName; + } + + public function requestUpdate() { + php_log(); + list($genericUpdate, $result) = $this->requestMetadata(Update::class, 'request_update'); + + if ($genericUpdate !== null) { + /** @var Update $genericUpdate */ + $genericUpdate->slug = $this->slug; + } + + $genericUpdate = $this->filterUpdateResult($genericUpdate, $result); + + return $genericUpdate; + } + + protected function filterUpdateResult($update, $httpResult = null) { + php_log(); + return apply_filters($this->getUniqueName('request_update_result'), $update, $httpResult); + } + + protected function getNoUpdateItemFields() { + php_log(); + $fields = parent::getNoUpdateItemFields(); + + unset($fields['requires_php']); + + return array_merge( + parent::getNoUpdateItemFields(), + array('generic' => $this->directoryName) + ); + } + + public function userCanInstallUpdates() { + php_log(); + return false; + } + + protected function createScheduler($checkPeriod) { + php_log(); + return null; + } + + public function isBeingUpgraded($upgrader = null) { + php_log(); + return false; + } + + public function addQueryArgFilter($callback){ + php_log(); + $this->addFilter('request_update_query_args', $callback); + } + + public function addHttpRequestArgFilter($callback) { + php_log(); + $this->addFilter('request_update_options', $callback); + } + + public function addResultFilter($callback) { + php_log(); + $this->addFilter('request_update_result', $callback, 10, 2); + } + + protected function createInstalledPackage() { + php_log(); + return null; + } + + protected function getInstalledTranslations() { + php_log(); + return array(); + } + } + +endif; diff --git a/lib/proxy-update-checker/Proxuc/Vcs/GenericUpdateChecker.php b/lib/proxy-update-checker/Proxuc/Vcs/GenericUpdateChecker.php new file mode 100644 index 0000000..ca59345 --- /dev/null +++ b/lib/proxy-update-checker/Proxuc/Vcs/GenericUpdateChecker.php @@ -0,0 +1,103 @@ +api = $api; + $this->api->setHttpFilterName($this->getUniqueName('request_update_options')); + + $this->genericAbsolutePath = trailingslashit($package_container) . $slug; + $this->genericFile = $slug . '/' . $generic_file_name . '.json'; + + $this->debugMode = (bool)(constant('WP_DEBUG')); + $this->metadataUrl = $api->getRepositoryUrl(); + $this->directoryName = basename(dirname($this->genericAbsolutePath)); + $this->slug = !empty($slug) ? $slug : $this->directoryName; + + $this->optionName = $optionName; + + if ( empty($this->optionName) ) { + + if ( $this->filterSuffix === '' ) { + $this->optionName = 'external_updates-' . $this->slug; + } else { + $this->optionName = $this->getUniqueName('external_updates'); + } + } + $this->package = new Package($this->genericAbsolutePath, $this); + $this->api->setSlug($this->slug); + } + + public function Vcs_getAbsoluteDirectoryPath() { + php_log(); + return trailingslashit($this->genericAbsolutePath); + } + + public function requestInfo($unused = null) { + php_log(); + $update = $this->requestUpdate(); + $info = null; + + if ($update && 'source_not_found' !== $update) { + + if (!empty($update->download_url)) { + $update->download_url = $this->api->signDownloadUrl($update->download_url); + } + + $info = array( + 'type' => 'Generic', + 'version' => $update->version, + 'main_file' => $this->genericFile, + 'download_url' => $update->download_url, + ); + } elseif ( 'source_not_found' === $update ) { + + return new WP_Error( + 'puc-no-update-source', + 'Could not retrieve version information from the repository for ' + . $this->slug . '.' + . 'This usually means that the update checker either can\'t connect ' + . 'to the repository or it\'s configured incorrectly.' + ); + } + + return $info; + } + + public function setBranch($branch) { + php_log(); + $this->branch = $branch; + + return $this; + } + + public function setAuthentication($credentials) { + php_log(); + $this->api->setAuthentication($credentials); + + return $this; + } + + public function getVcsApi() { + php_log(); + return $this->api; + } + } + +endif; diff --git a/lib/proxy-update-checker/proxy-update-checker.php b/lib/proxy-update-checker/proxy-update-checker.php index 9e018ac..bc3a0c7 100644 --- a/lib/proxy-update-checker/proxy-update-checker.php +++ b/lib/proxy-update-checker/proxy-update-checker.php @@ -10,6 +10,7 @@ use YahnisElsts\PluginUpdateChecker\v5p3\Plugin; use YahnisElsts\PluginUpdateChecker\v5p3\Theme; +use Anyape\ProxyUpdateChecker\Generic; use YahnisElsts\PluginUpdateChecker\v5p3\Vcs; use YahnisElsts\PluginUpdateChecker\v5p3\Vcs\GitHubApi; use YahnisElsts\PluginUpdateChecker\v5p3\Vcs\GitLabApi; @@ -23,6 +24,7 @@ Proxuc_Factory::setCheckerVersion('1.0'); Proxuc_Factory::addVersion('Vcs_PluginUpdateChecker', 'Proxuc_Vcs_PluginUpdateChecker', '1.0'); Proxuc_Factory::addVersion('Vcs_ThemeUpdateChecker', 'Proxuc_Vcs_ThemeUpdateChecker', '1.0'); +Proxuc_Factory::addVersion('Vcs_GenericUpdateChecker', 'Proxuc_Vcs_GenericUpdateChecker', '1.0'); Proxuc_Factory::setApiVersion('5.0'); Proxuc_Factory::addVersion('GitHubApi', 'GitHubApi', '5.3'); diff --git a/lib/wp-update-server-extended/includes/Wpupe/ZipMetadataParser.php b/lib/wp-update-server-extended/includes/Wpupe/ZipMetadataParser.php index f464320..c3f56e7 100644 --- a/lib/wp-update-server-extended/includes/Wpupe/ZipMetadataParser.php +++ b/lib/wp-update-server-extended/includes/Wpupe/ZipMetadataParser.php @@ -9,11 +9,13 @@ class Wpup_ZipMetadataParser_Extended extends Wpup_ZipMetadataParser { 'Version' => 'version', 'PluginURI' => 'homepage', 'ThemeURI' => 'homepage', + 'Homepage' => 'homepage', 'Author' => 'author', 'AuthorURI' => 'author_homepage', 'RequiresPHP' => 'requires_php', 'Description' => 'description', - 'DetailsURI' => 'details_url', //Only for themes. + 'DetailsURI' => 'details_url', //Only for themes + 'PackageData' => 'package_data', //Only for generic 'Depends' => 'depends', // plugin-dependencies plugin 'Provides' => 'provides', // plugin-dependencies plugin ); @@ -31,11 +33,30 @@ protected function extractMetadata(){ $this->setLastUpdateDate(); $this->setInfoFromAssets(); $this->setSlug(); + $this->setType(); } else { - throw new Wpup_InvalidPackageException(sprintf('The specified file %s does not contain a valid WordPress plugin or theme.', $this->filename)); + throw new Wpup_InvalidPackageException(sprintf('The specified file %s does not contain a valid Generic package or WordPress plugin or theme.', $this->filename)); } } + protected function settype(){ + $this->metadata['type'] = $this->packageInfo['type']; + } + + protected function setSlug(){ + + if ('plugin' === $this->packageInfo['type']) { + $mainFile = $this->packageInfo['pluginFile']; + } elseif ('theme' === $this->packageInfo['type']) { + $mainFile = $this->packageInfo['stylesheet']; + } elseif ('generic' === $this->packageInfo['type']) { + $mainFile = $this->packageInfo['genericFile']; + } + + $this->metadata['slug'] = basename(dirname(strtolower($mainFile))); + //Idea: Warn the user if the package doesn't match the expected "/slug/other-files" layout. + } + /** * Extract icons and banners info for plugins */ diff --git a/lib/wp-update-server-extended/includes/extension-meta/extension-meta.php b/lib/wp-update-server-extended/includes/extension-meta/extension-meta.php index 7fb1201..4392b12 100644 --- a/lib/wp-update-server-extended/includes/extension-meta/extension-meta.php +++ b/lib/wp-update-server-extended/includes/extension-meta/extension-meta.php @@ -23,9 +23,11 @@ public static function parsePackage($packageFilename, $applyMarkdown = false){ $readme = null; $pluginFile = null; $stylesheet = null; + $genericFile = null; $type = null; $assets = null; $entries = $zip->listEntries(); + $slug = str_replace('.zip', '', basename($packageFilename)); for ($fileIndex = 0; ($fileIndex < count($entries)) && (empty($readme) || empty($header)); $fileIndex++){ $info = $entries[$fileIndex]; @@ -53,7 +55,8 @@ public static function parsePackage($packageFilename, $applyMarkdown = false){ if (empty($header) && (strtolower(basename($fileName)) === 'style.css')) { $fileContents = substr($zip->getFileContents($info), 0, 8*1024); $header = self::getThemeHeaders($fileContents); - if ( !empty($header) ){ + + if (!empty($header)){ $stylesheet = $fileName; $type = 'theme'; } @@ -63,18 +66,30 @@ public static function parsePackage($packageFilename, $applyMarkdown = false){ if (empty($header) && ($extension === 'php')){ $fileContents = substr($zip->getFileContents($info), 0, 8*1024); $header = self::getPluginHeaders($fileContents); - if ( !empty($header) ){ + + if (!empty($header)){ $pluginFile = $fileName; $type = 'plugin'; $assets = self::getAssetsHeaders($fileContents); } } + + //Generic info file? + if (empty($header) && ($extension === 'json') && (basename($fileName) === 'wppus.json')){ + $fileContents = substr($zip->getFileContents($info), 0, 8*1024); + $header = json_decode($fileContents, true); + + if (!empty($header)){ + $genericFile = $fileName; + $type = 'generic'; + } + } } if (empty($type)){ return false; } else { - return compact('header', 'assets', 'readme', 'pluginFile', 'stylesheet', 'type'); + return compact('header', 'assets', 'readme', 'pluginFile', 'stylesheet', 'genericFile', 'type'); } }
- + - +

- +
- +
- +
- -

-
- - - -

- -
- -
- -
- +