Skip to content

Commit 8ae3588

Browse files
authored
Merge pull request #138 from wp-cli/fix/disable-http-request-retry-by-default
Add `--insecure` flag to `package install` command
2 parents d12e507 + da4a502 commit 8ae3588

1 file changed

Lines changed: 46 additions & 25 deletions

File tree

‎src/Package_Command.php‎

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)