parent
64fc8ffe3d
commit
8845ea467a
|
@ -44,6 +44,7 @@ class RemoteFilesystem
|
||||||
private $degradedMode = false;
|
private $degradedMode = false;
|
||||||
private $redirects;
|
private $redirects;
|
||||||
private $maxRedirects = 20;
|
private $maxRedirects = 20;
|
||||||
|
private $bitBucketUrlsTriedWithoutAuth = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -175,27 +176,6 @@ class RemoteFilesystem
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @link https://github.com/composer/composer/issues/5584
|
|
||||||
*
|
|
||||||
* @param string $urlToBitBucketFile URL to a file at bitbucket.org.
|
|
||||||
*
|
|
||||||
* @return bool Whether the given URL is a public BitBucket download which requires no authentication.
|
|
||||||
*/
|
|
||||||
public static function urlIsPublicBitBucketDownload($urlToBitBucketFile)
|
|
||||||
{
|
|
||||||
$path = parse_url($urlToBitBucketFile, PHP_URL_PATH);
|
|
||||||
|
|
||||||
// Path for a public download follows this pattern /{user}/{repo}/downloads/{whatever}
|
|
||||||
// {@link https://blog.bitbucket.org/2009/04/12/new-feature-downloads/}
|
|
||||||
$pathParts = explode('/', $path);
|
|
||||||
if (count($pathParts) >= 4 && $pathParts[2] != 'downloads') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get file content or copy action.
|
* Get file content or copy action.
|
||||||
*
|
*
|
||||||
|
@ -267,7 +247,12 @@ class RemoteFilesystem
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['bitbucket-token'])) {
|
if (isset($options['bitbucket-token'])) {
|
||||||
|
// First time be optimistic and do not use the token for a BitBucket download.
|
||||||
|
if (isset($this->bitBucketUrlsTriedWithoutAuth[$origFileUrl]) && $this->bitBucketUrlsTriedWithoutAuth[$origFileUrl]) {
|
||||||
$fileUrl .= (false === strpos($fileUrl,'?') ? '?' : '&') . 'access_token=' . $options['bitbucket-token'];
|
$fileUrl .= (false === strpos($fileUrl,'?') ? '?' : '&') . 'access_token=' . $options['bitbucket-token'];
|
||||||
|
} else {
|
||||||
|
$this->bitBucketUrlsTriedWithoutAuth[$origFileUrl] = true;
|
||||||
|
}
|
||||||
unset($options['bitbucket-token']);
|
unset($options['bitbucket-token']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,9 +348,7 @@ class RemoteFilesystem
|
||||||
|
|
||||||
// check for bitbucket login page asking to authenticate
|
// check for bitbucket login page asking to authenticate
|
||||||
if ($originUrl === 'bitbucket.org'
|
if ($originUrl === 'bitbucket.org'
|
||||||
&& !self::urlIsPublicBitBucketDownload($fileUrl)
|
&& substr($fileUrl, 0, 37) === 'https://bitbucket.org/account/signin/'
|
||||||
&& substr($fileUrl, -4) === '.zip'
|
|
||||||
&& preg_match('{^text/html\b}i', $contentType)
|
|
||||||
) {
|
) {
|
||||||
$result = false;
|
$result = false;
|
||||||
if ($this->retryAuthFailure) {
|
if ($this->retryAuthFailure) {
|
||||||
|
|
|
@ -191,6 +191,84 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides URLs to public downloads at BitBucket.
|
||||||
|
*
|
||||||
|
* @return string[][]
|
||||||
|
*/
|
||||||
|
public function provideBitbucketPublicDownloadUrls()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('https://bitbucket.org/berlinger-rarents/my-public-repo-with-downloads/downloads/composer-unit-test-download-me.txt', '1234'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a BitBucket public download is correctly retrieved.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param string $contents
|
||||||
|
* @dataProvider provideBitbucketPublicDownloadUrls
|
||||||
|
*/
|
||||||
|
public function testBitBucketPublicDownload($url, $contents)
|
||||||
|
{
|
||||||
|
$io = $this
|
||||||
|
->getMockBuilder('Composer\IO\ConsoleIO')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$rfs = new RemoteFilesystem($io);
|
||||||
|
$hostname = parse_url($url, PHP_URL_HOST);
|
||||||
|
|
||||||
|
$result = $rfs->getContents($hostname, $url, false);
|
||||||
|
|
||||||
|
$this->assertEquals($contents, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a BitBucket public download is correctly retrieved when `bitbucket-oauth` is configured.
|
||||||
|
*
|
||||||
|
* @param string $url
|
||||||
|
* @param string $contents
|
||||||
|
* @dataProvider provideBitbucketPublicDownloadUrls
|
||||||
|
*/
|
||||||
|
public function testBitBucketPublicDownloadWithAuthConfigured($url, $contents)
|
||||||
|
{
|
||||||
|
$io = $this
|
||||||
|
->getMockBuilder('Composer\IO\ConsoleIO')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$config = $this
|
||||||
|
->getMockBuilder('Composer\Config')
|
||||||
|
->getMock();
|
||||||
|
$config
|
||||||
|
->method('get')
|
||||||
|
->withAnyParameters()
|
||||||
|
->willReturn(array());
|
||||||
|
|
||||||
|
$io
|
||||||
|
->method('hasAuthentication')
|
||||||
|
->with('bitbucket.org')
|
||||||
|
->willReturn(true);
|
||||||
|
$io
|
||||||
|
->method('getAuthentication')
|
||||||
|
->with('bitbucket.org')
|
||||||
|
->willReturn(array(
|
||||||
|
'username' => 'x-token-auth',
|
||||||
|
// This token is fake, but it matches a valid token's pattern.
|
||||||
|
'password' => '1A0yeK5Po3ZEeiiRiMWLivS0jirLdoGuaSGq9NvESFx1Fsdn493wUDXC8rz_1iKVRTl1GINHEUCsDxGh5lZ='
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
$rfs = new RemoteFilesystem($io, $config);
|
||||||
|
$hostname = parse_url($url, PHP_URL_HOST);
|
||||||
|
|
||||||
|
$result = $rfs->getContents($hostname, $url, false);
|
||||||
|
|
||||||
|
$this->assertEquals($contents, $result);
|
||||||
|
}
|
||||||
|
|
||||||
protected function callGetOptionsForUrl($io, array $args = array(), array $options = array(), $fileUrl = '')
|
protected function callGetOptionsForUrl($io, array $args = array(), array $options = array(), $fileUrl = '')
|
||||||
{
|
{
|
||||||
$fs = new RemoteFilesystem($io, null, $options);
|
$fs = new RemoteFilesystem($io, null, $options);
|
||||||
|
|
Loading…
Reference in New Issue