@@ -193,6 +193,9 @@ public function browse( $_, $assoc_args ) {
193193 * Names can optionally include a version constraint
194194 * (e.g. wp-cli/server-command:@stable).
195195 *
196+ * [--insecure]
197+ * : Retry downloads without certificate validation if TLS handshake fails. Note: This makes the request vulnerable to a MITM attack.
198+ *
196199 * ## EXAMPLES
197200 *
198201 * # Install a package hosted at a git URL.
@@ -210,6 +213,8 @@ public function browse( $_, $assoc_args ) {
210213 public function install ( $ args , $ assoc_args ) {
211214 list ( $ package_name ) = $ args ;
212215
216+ $ insecure = (bool ) Utils \get_flag_value ( $ assoc_args , 'insecure ' , false );
217+
213218 $ this ->set_composer_auth_env_var ();
214219 $ git_package = false ;
215220 $ dir_package = false ;
@@ -218,7 +223,7 @@ public function install( $args, $assoc_args ) {
218223 $ git_package = $ package_name ;
219224 preg_match ( '#([^:\/]+\/[^\/]+)\.git# ' , $ package_name , $ matches );
220225 if ( ! empty ( $ matches [1 ] ) ) {
221- $ package_name = $ this ->check_git_package_name ( $ matches [1 ], $ package_name );
226+ $ package_name = $ this ->check_git_package_name ( $ matches [1 ], $ package_name, '' , $ insecure );
222227 } else {
223228 WP_CLI ::error ( "Couldn't parse package name from expected path '<name>/<package>'. " );
224229 }
@@ -231,6 +236,7 @@ public function install( $args, $assoc_args ) {
231236 $ options = [
232237 'timeout ' => 600 ,
233238 'filename ' => $ temp ,
239+ 'insecure ' => $ insecure ,
234240 ];
235241 $ response = Utils \http_request ( 'GET ' , $ package_name , null , [], $ options );
236242 if ( 20 !== (int ) substr ( $ response ->status_code , 0 , 2 ) ) {
@@ -286,10 +292,10 @@ public function install( $args, $assoc_args ) {
286292 if ( $ this ->is_git_repository ( $ package ) ) {
287293 $ git_package = $ package ;
288294 if ( '@stable ' === $ version ) {
289- $ tag = $ this ->get_github_latest_release_tag ( $ package_name );
295+ $ tag = $ this ->get_github_latest_release_tag ( $ package_name, $ insecure );
290296 $ version = $ this ->guess_version_constraint_from_tag ( $ tag );
291297 }
292- $ package_name = $ this ->check_github_package_name ( $ package_name , $ version );
298+ $ package_name = $ this ->check_github_package_name ( $ package_name , $ version, $ insecure );
293299 }
294300 } elseif ( $ package_name !== $ package ->getPrettyName () ) {
295301 // BC support for specifying lowercase names for mixed-case package index packages - don't bother warning.
@@ -376,6 +382,9 @@ public function install( $args, $assoc_args ) {
376382 } catch ( Exception $ e ) {
377383 WP_CLI ::warning ( $ e ->getMessage () );
378384 }
385+
386+ // TODO: The --insecure flag should cause another Composer run with verify disabled.
387+
379388 WP_CLI ::log ( '--- ' );
380389
381390 if ( 0 === $ res ) {
@@ -510,6 +519,8 @@ public function update() {
510519 }
511520 WP_CLI ::log ( '--- ' );
512521
522+ // TODO: The --insecure (to be added here) flag should cause another Composer run with verify disabled.
523+
513524 if ( 0 === $ res ) {
514525 WP_CLI ::success ( 'Packages updated. ' );
515526 } else {
@@ -765,8 +776,11 @@ function( $package ) {
765776 *
766777 * This method first checks the deprecated package index, for BC reasons,
767778 * and then falls back to the corresponding GitHub URL.
779+ *
780+ * @param string $package_name Name of the package to get.
781+ * @param bool $insecure Whether to insecurely retry downloads that failed TLS handshake.
768782 */
769- private function get_package_by_shortened_identifier ( $ package_name ) {
783+ private function get_package_by_shortened_identifier ( $ package_name, $ insecure = false ) {
770784 // Check the package index first, so we don't break existing behavior.
771785 $ lc_package_name = strtolower ( $ package_name ); // For BC check.
772786 foreach ( $ this ->get_community_packages () as $ package ) {
@@ -779,9 +793,11 @@ private function get_package_by_shortened_identifier( $package_name ) {
779793 }
780794 }
781795
796+ $ options = [ 'insecure ' => $ insecure ];
797+
782798 // Check if the package exists on Packagist.
783799 $ url = "https://repo.packagist.org/p/ {$ package_name }.json " ;
784- $ response = Utils \http_request ( 'GET ' , $ url );
800+ $ response = Utils \http_request ( 'GET ' , $ url, null , [], $ options );
785801 if ( 20 === (int ) substr ( $ response ->status_code , 0 , 2 ) ) {
786802 return $ package_name ;
787803 }
@@ -790,7 +806,7 @@ private function get_package_by_shortened_identifier( $package_name ) {
790806 $ url = "https://github.com/ {$ package_name }.git " ;
791807 $ github_token = getenv ( 'GITHUB_TOKEN ' ); // Use GITHUB_TOKEN if available to avoid authorization failures or rate-limiting.
792808 $ headers = $ github_token ? [ 'Authorization ' => 'token ' . $ github_token ] : [];
793- $ response = Utils \http_request ( 'GET ' , $ url , null /*data*/ , $ headers );
809+ $ response = Utils \http_request ( 'GET ' , $ url , null /*data*/ , $ headers, $ options );
794810 if ( 20 === (int ) substr ( $ response ->status_code , 0 , 2 ) ) {
795811 return $ url ;
796812 }
@@ -1050,17 +1066,18 @@ private function is_git_repository( $package ) {
10501066 /**
10511067 * Checks that `$package_name` matches the name in composer.json at Github.com, and return corrected value if not.
10521068 *
1053- * @string $package_name Package name to check.
1054- * @string $version Optional. Package version. Default 'master'.
1055- * @string Package name, possibly changed to match that in repo .
1069+ * @param string $package_name Package name to check.
1070+ * @param string $version Optional. Package version. Default 'master'.
1071+ * @param bool $insecure Optional. Whether to insecurely retry downloads that failed TLS handshake .
10561072 */
1057- private function check_github_package_name ( $ package_name , $ version = '' ) {
1073+ private function check_github_package_name ( $ package_name , $ version = '' , $ insecure = false ) {
10581074 // Generate raw git URL of composer.json file.
10591075 $ raw_content_url = 'https://raw.githubusercontent.com/ ' . $ package_name . '/ ' . $ this ->get_raw_git_version ( $ version ) . '/composer.json ' ;
10601076 $ github_token = getenv ( 'GITHUB_TOKEN ' ); // Use GITHUB_TOKEN if available to avoid authorization failures or rate-limiting.
10611077 $ headers = $ github_token ? [ 'Authorization ' => 'token ' . $ github_token ] : [];
1078+ $ options = [ 'insecure ' => $ insecure ];
10621079
1063- $ response = Utils \http_request ( 'GET ' , $ raw_content_url , null /*data*/ , $ headers );
1080+ $ response = Utils \http_request ( 'GET ' , $ raw_content_url , null /*data*/ , $ headers, $ options );
10641081 if ( 20 !== (int ) substr ( $ response ->status_code , 0 , 2 ) ) {
10651082 // Could not get composer.json. Possibly private so warn and return best guess from input (always xxx/xxx).
10661083 WP_CLI ::warning ( sprintf ( "Couldn't download composer.json file from '%s' (HTTP code %d). Presuming package name is '%s'. " , $ raw_content_url , $ response ->status_code , $ package_name ) );
@@ -1090,31 +1107,34 @@ private function check_github_package_name( $package_name, $version = '' ) {
10901107 /**
10911108 * Checks that `$package_name` matches the name in composer.json at the corresponding upstream repository, and return corrected value if not.
10921109 *
1093- * @string $package_name Package name to check.
1094- * @string $version Optional. Package version. Default 'master'.
1095- * @string Package name, possibly changed to match that in repo.
1110+ * @param string $package_name Package name to check.
1111+ * @param string $urrl URL to fetch the package from.
1112+ * @param string $version Optional. Package version. Default 'master'.
1113+ * @param bool $insecure Optional. Whether to insecurely retry downloads that failed TLS handshake.
10961114 */
1097- private function check_git_package_name ( $ package_name , $ url = '' , $ version = '' ) {
1115+ private function check_git_package_name ( $ package_name , $ url = '' , $ version = '' , $ insecure = false ) {
10981116 if ( $ url && ( strpos ( $ url , '://gitlab.com/ ' ) !== false ) || ( strpos ( $ url , 'git@gitlab.com: ' ) !== false ) ) {
1099- return $ this ->check_gitlab_package_name ( $ package_name );
1117+ return $ this ->check_gitlab_package_name ( $ package_name, $ version , $ insecure );
11001118 }
11011119
1102- return $ this ->check_github_package_name ( $ package_name );
1120+ return $ this ->check_github_package_name ( $ package_name, $ version , $ insecure );
11031121 }
11041122
11051123 /**
11061124 * Checks that `$package_name` matches the name in composer.json at GitLab.com, and return corrected value if not.
11071125 *
1108- * @string $package_name Package name to check.
1109- * @string $version Optional. Package version. Default 'master'.
1110- * @string Package name, possibly changed to match that in repo .
1126+ * @param string $package_name Package name to check.
1127+ * @param string $version Optional. Package version. Default 'master'.
1128+ * @param bool $insecure Optional. Whether to insecurely retry downloads that failed TLS handshake .
11111129 */
1112- private function check_gitlab_package_name ( $ package_name , $ version = '' ) {
1130+ private function check_gitlab_package_name ( $ package_name , $ version = '' , $ insecure = false ) {
11131131 // Generate raw git URL of composer.json file.
11141132 $ raw_content_public_url = 'https://gitlab.com/ ' . $ package_name . '/-/raw/ ' . $ this ->get_raw_git_version ( $ version ) . '/composer.json ' ;
11151133 $ raw_content_private_url = 'https://gitlab.com/api/v4/projects/ ' . rawurlencode ( $ package_name ) . '/repository/files/composer.json/raw?ref= ' . $ this ->get_raw_git_version ( $ version );
11161134
1117- $ response = Utils \http_request ( 'GET ' , $ raw_content_public_url , null /*data*/ );
1135+ $ options = [ 'insecure ' => $ insecure ];
1136+
1137+ $ response = Utils \http_request ( 'GET ' , $ raw_content_public_url , null /*data*/ , [], $ options );
11181138 if ( $ response ->status_code < 200 || $ response ->status_code >= 300 ) {
11191139 // Could not get composer.json. Possibly private so warn and return best guess from input (always xxx/xxx).
11201140 WP_CLI ::warning ( sprintf ( "Couldn't download composer.json file from '%s' (HTTP code %d). Presuming package name is '%s'. " , $ raw_content_public_url , $ response ->status_code , $ package_name ) );
@@ -1124,7 +1144,7 @@ private function check_gitlab_package_name( $package_name, $version = '' ) {
11241144 if ( strpos ( $ response ->headers ['content-type ' ], 'text/html ' ) === 0 ) {
11251145 $ gitlab_token = getenv ( 'GITLAB_TOKEN ' ); // Use GITLAB_TOKEN if available to avoid authorization failures or rate-limiting.
11261146 $ headers = $ gitlab_token ? [ 'PRIVATE-TOKEN ' => $ gitlab_token ] : [];
1127- $ response = Utils \http_request ( 'GET ' , $ raw_content_private_url , null /*data*/ , $ headers );
1147+ $ response = Utils \http_request ( 'GET ' , $ raw_content_private_url , null /*data*/ , $ headers, $ options );
11281148
11291149 if ( $ response ->status_code < 200 || $ response ->status_code >= 300 ) {
11301150 // Could not get composer.json. Possibly private so warn and return best guess from input (always xxx/xxx).
@@ -1186,9 +1206,10 @@ private function get_raw_git_version( $version ) {
11861206 *
11871207 * @return string Release tag.
11881208 */
1189- private function get_github_latest_release_tag ( $ package_name ) {
1209+ private function get_github_latest_release_tag ( $ package_name, $ insecure ) {
11901210 $ url = "https://api.github.com/repos/ {$ package_name }/releases/latest " ;
1191- $ response = Utils \http_request ( 'GET ' , $ url );
1211+ $ options = [ 'insecure ' => $ insecure ];
1212+ $ response = Utils \http_request ( 'GET ' , $ url , null , [], $ options );
11921213 if ( 20 !== (int ) substr ( $ response ->status_code , 0 , 2 ) ) {
11931214 WP_CLI ::warning ( 'Could not guess stable version from GitHub repository, falling back to master branch ' );
11941215 return 'master ' ;
0 commit comments