1
0
Fork 0

Make use of new hashed provider filenames, fixes #1431, refs composer/packagist#283

pull/1584/merge
Jordi Boggiano 2013-02-21 16:50:04 +01:00
parent b4c2347b24
commit 9521d1e7ad
1 changed files with 56 additions and 18 deletions

View File

@ -33,9 +33,11 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
protected $url; protected $url;
protected $baseUrl; protected $baseUrl;
protected $io; protected $io;
protected $rfs;
protected $cache; protected $cache;
protected $notifyUrl; protected $notifyUrl;
protected $hasProviders = false; protected $hasProviders = false;
protected $providersUrl;
protected $providerListing; protected $providerListing;
protected $providers = array(); protected $providers = array();
protected $providersByUid = array(); protected $providersByUid = array();
@ -72,8 +74,9 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
$this->url = $repoConfig['url']; $this->url = $repoConfig['url'];
$this->baseUrl = rtrim(preg_replace('{^(.*)(?:/packages.json)?(?:[?#].*)?$}', '$1', $this->url), '/'); $this->baseUrl = rtrim(preg_replace('{^(.*)(?:/packages.json)?(?:[?#].*)?$}', '$1', $this->url), '/');
$this->io = $io; $this->io = $io;
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url)); $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$');
$this->loader = new ArrayLoader(); $this->loader = new ArrayLoader();
$this->rfs = new RemoteFilesystem($this->io, $this->options);
} }
public function setRootAliases(array $rootAliases) public function setRootAliases(array $rootAliases)
@ -201,17 +204,31 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
$this->loadProviderListings($this->loadRootServerFile()); $this->loadProviderListings($this->loadRootServerFile());
} }
$url = 'p/'.$name.'.json'; if ($this->providersUrl) {
// package does not exist in this repo
if (!isset($this->providerListing[$name])) {
return array();
}
// package does not exist in this repo $hash = $this->providerListing[$name]['sha256'];
if (!isset($this->providerListing[$url])) { $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl);
return array(); $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
} else {
// BC handling for old providers-includes
$url = 'p/'.$name.'.json';
// package does not exist in this repo
if (!isset($this->providerListing[$url])) {
return array();
}
$hash = $this->providerListing[$url]['sha256'];
$cacheKey = null;
} }
if ($this->cache->sha256($url) === $this->providerListing[$url]['sha256']) { if ($this->cache->sha256($cacheKey) === $hash) {
$packages = json_decode($this->cache->read($url), true); $packages = json_decode($this->cache->read($cacheKey), true);
} else { } else {
$packages = $this->fetchFile($url, null, $this->providerListing[$url]['sha256']); $packages = $this->fetchFile($url, $cacheKey, $hash);
} }
$this->providers[$name] = array(); $this->providers[$name] = array();
@ -311,11 +328,18 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
$data = $this->fetchFile($jsonUrl, 'packages.json'); $data = $this->fetchFile($jsonUrl, 'packages.json');
// TODO remove this BC notify_batch support
if (!empty($data['notify_batch'])) { if (!empty($data['notify_batch'])) {
if ('/' === $data['notify_batch'][0]) { $notifyBatchUrl = $data['notify_batch'];
$this->notifyUrl = preg_replace('{(https?://[^/]+).*}i', '$1' . $data['notify_batch'], $this->url); }
if (!empty($data['notify-batch'])) {
$notifyBatchUrl = $data['notify-batch'];
}
if (!empty($notifyBatchUrl)) {
if ('/' === $notifyBatchUrl[0]) {
$this->notifyUrl = preg_replace('{(https?://[^/]+).*}i', '$1' . $notifyBatchUrl, $this->url);
} else { } else {
$this->notifyUrl = $data['notify_batch']; $this->notifyUrl = $notifyBatchUrl;
} }
} }
@ -327,6 +351,15 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
} }
} }
if (!empty($data['providers-url'])) {
if ('/' === $data['providers-url'][0]) {
$this->providersUrl = preg_replace('{(https?://[^/]+).*}i', '$1' . $data['providers-url'], $this->url);
} else {
$this->providersUrl = $data['providers-url'];
}
$this->hasProviders = true;
}
if (!empty($data['providers']) || !empty($data['providers-includes'])) { if (!empty($data['providers']) || !empty($data['providers-includes'])) {
$this->hasProviders = true; $this->hasProviders = true;
} }
@ -350,8 +383,14 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
$this->providerListing = array_merge($this->providerListing, $data['providers']); $this->providerListing = array_merge($this->providerListing, $data['providers']);
} }
if (isset($data['providers-includes'])) { if ($this->providersUrl && isset($data['provider-includes'])) {
foreach ($data['providers-includes'] as $include => $metadata) { $includes = $data['provider-includes'];
} elseif (isset($data['providers-includes'])) {
// BC layer for old-style providers-includes
$includes = $data['providers-includes'];
}
if (!empty($includes)) {
foreach ($includes as $include => $metadata) {
if ($this->cache->sha256($include) === $metadata['sha256']) { if ($this->cache->sha256($include) === $metadata['sha256']) {
$includedData = json_decode($this->cache->read($include), true); $includedData = json_decode($this->cache->read($include), true);
} else { } else {
@ -421,10 +460,8 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
$retries = 3; $retries = 3;
while ($retries--) { while ($retries--) {
try { try {
$json = new JsonFile($filename, new RemoteFilesystem($this->io, $this->options)); $json = $this->rfs->getContents($filename, $filename, false);
$data = $json->read(); if ($sha256 && $sha256 !== hash('sha256', $json)) {
$encoded = json_encode($data);
if ($sha256 && $sha256 !== hash('sha256', $encoded)) {
if ($retries) { if ($retries) {
usleep(100); usleep(100);
@ -434,7 +471,8 @@ class ComposerRepository extends ArrayRepository implements StreamableRepository
// TODO throw SecurityException and abort once we are sure this can not happen accidentally // TODO throw SecurityException and abort once we are sure this can not happen accidentally
$this->io->write('<warning>The contents of '.$filename.' do not match its signature, this is most likely due to a temporary glitch but could indicate a man-in-the-middle attack. Try running composer again and please report it if it still persists.</warning>'); $this->io->write('<warning>The contents of '.$filename.' do not match its signature, this is most likely due to a temporary glitch but could indicate a man-in-the-middle attack. Try running composer again and please report it if it still persists.</warning>');
} }
$this->cache->write($cacheKey, $encoded); $data = JsonFile::parseJson($json, $filename);
$this->cache->write($cacheKey, $json);
break; break;
} catch (\Exception $e) { } catch (\Exception $e) {