Jelajahi Sumber

Always check for OAuth token in git config, fixes #1243

Jordi Boggiano 12 tahun lalu
induk
melakukan
bebd1ce9c7

+ 5 - 1
src/Composer/Downloader/FileDownloader.php

@@ -80,7 +80,11 @@ class FileDownloader implements DownloaderInterface
                 if (404 === $e->getCode() && 'github.com' === parse_url($processUrl, PHP_URL_HOST)) {
                     $message = "\n".'Could not fetch '.$processUrl.', enter your GitHub credentials to access private repos';
                     $gitHubUtil = new GitHub($this->io, $this->config, null, $this->rfs);
-                    $gitHubUtil->authorizeOAuth('github.com', $message);
+                    if (!$gitHubUtil->authorizeOAuth('github.com')
+                        && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively('github.com', $message))
+                    ) {
+                        throw $e;
+                    }
                     $this->rfs->copy(parse_url($processUrl, PHP_URL_HOST), $processUrl, $fileName);
                 } else {
                     throw $e;

+ 13 - 8
src/Composer/Downloader/GitDownloader.php

@@ -285,19 +285,24 @@ class GitDownloader extends VcsDownloader
         $command = call_user_func($commandCallable, $url);
         if (0 !== $this->process->execute($command, $handler)) {
             // private github repository without git access, try https with auth
-            if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match) && $this->io->isInteractive()) {
+            if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match)) {
                 if (!$this->io->hasAuthorization($match[1])) {
-                    $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
                     $gitHubUtil = new GitHub($this->io, $this->config, $this->process);
-                    $gitHubUtil->authorizeOAuth($match[1], $message);
+                    $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
+
+                    if (!$gitHubUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
+                        $gitHubUtil->authorizeOAuthInteractively($match[1], $message);
+                    }
                 }
 
-                $auth = $this->io->getAuthorization($match[1]);
-                $url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@'.$match[1].'/'.$match[2].'.git';
+                if ($this->io->hasAuthorization($match[1])) {
+                    $auth = $this->io->getAuthorization($match[1]);
+                    $url = 'https://'.$auth['username'] . ':' . $auth['password'] . '@'.$match[1].'/'.$match[2].'.git';
 
-                $command = call_user_func($commandCallable, $url);
-                if (0 === $this->process->execute($command, $handler)) {
-                    return;
+                    $command = call_user_func($commandCallable, $url);
+                    if (0 === $this->process->execute($command, $handler)) {
+                        return;
+                    }
                 }
             }
 

+ 14 - 10
src/Composer/Repository/Vcs/GitHubDriver.php

@@ -244,6 +244,8 @@ class GitHubDriver extends VcsDriver
         try {
             return parent::getContents($url);
         } catch (TransportException $e) {
+            $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
+
             switch ($e->getCode()) {
                 case 401:
                 case 404:
@@ -252,17 +254,25 @@ class GitHubDriver extends VcsDriver
                         throw $e;
                     }
 
+                    if ($gitHubUtil->authorizeOAuth($this->originUrl)) {
+                        return parent::getContents($url);
+                    }
+
                     if (!$this->io->isInteractive()) {
-                        return $this->attemptCloneFallback($e);
+                        return $this->attemptCloneFallback();
                     }
 
-                    $this->authorizeOAuth('Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
+                    $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
 
                     return parent::getContents($url);
 
                 case 403:
+                    if (!$this->io->hasAuthorization($this->originUrl) && $gitHubUtil->authorizeOAuth($this->originUrl)) {
+                        return parent::getContents($url);
+                    }
+
                     if (!$this->io->isInteractive() && $fetchingRepoData) {
-                        return $this->attemptCloneFallback($e);
+                        return $this->attemptCloneFallback();
                     }
 
                     $rateLimited = false;
@@ -278,7 +288,7 @@ class GitHubDriver extends VcsDriver
                             throw $e;
                         }
 
-                        $this->authorizeOAuth('API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)');
+                        $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)');
 
                         return parent::getContents($url);
                     }
@@ -346,10 +356,4 @@ class GitHubDriver extends VcsDriver
             throw $e;
         }
     }
-
-    protected function authorizeOAuth($message)
-    {
-        $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
-        $gitHubUtil->authorizeOAuth($this->originUrl, $message);
-    }
 }

+ 21 - 5
src/Composer/Util/GitHub.php

@@ -44,20 +44,36 @@ class GitHub
     }
 
     /**
-     * Authorizes a GitHub domain via OAuth
+     * Attempts to authorize a GitHub domain via OAuth
      *
      * @param string $originUrl The host this GitHub instance is located at
-     * @param string $message   The reason this authorization is required
+     * @return bool  true on success
      */
-    public function authorizeOAuth($originUrl, $message = null)
+    public function authorizeOAuth($originUrl)
     {
+        if ('github.com' !== $originUrl) {
+            return false;
+        }
+
         // if available use token from git config
         if (0 === $this->process->execute('git config github.accesstoken', $output)) {
             $this->io->setAuthorization($originUrl, trim($output), 'x-oauth-basic');
 
-            return;
+            return true;
         }
 
+        return false;
+    }
+
+    /**
+     * Authorizes a GitHub domain interactively via OAuth
+     *
+     * @param string $originUrl The host this GitHub instance is located at
+     * @param string $message   The reason this authorization is required
+     * @return bool  true on success
+     */
+    public function authorizeOAuthInteractively($originUrl, $message = null)
+    {
         $attemptCounter = 0;
 
         if ($message) {
@@ -105,7 +121,7 @@ class GitHub
             $githubTokens[$originUrl] = $contents['token'];
             $this->config->getConfigSource()->addConfigSetting('github-oauth', $githubTokens);
 
-            return;
+            return true;
         }
 
         throw new \RuntimeException("Invalid GitHub credentials 5 times in a row, aborting.");

+ 11 - 6
tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php

@@ -263,31 +263,36 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase
         $fs->removeDirectory(sys_get_temp_dir() . '/composer-test');
 
         $process->expects($this->at(0))
+            ->method('execute')
+            ->with($this->equalTo('git config github.accesstoken'))
+            ->will($this->returnValue(1));
+
+        $process->expects($this->at(1))
             ->method('execute')
             ->with($this->stringContains($repoSshUrl))
             ->will($this->returnValue(0));
 
-        $process->expects($this->at(1))
+        $process->expects($this->at(2))
             ->method('execute')
             ->with($this->stringContains('git tag'));
 
-        $process->expects($this->at(2))
+        $process->expects($this->at(3))
             ->method('splitLines')
             ->will($this->returnValue(array($identifier)));
 
-        $process->expects($this->at(3))
+        $process->expects($this->at(4))
             ->method('execute')
             ->with($this->stringContains('git branch --no-color --no-abbrev -v'));
 
-        $process->expects($this->at(4))
+        $process->expects($this->at(5))
             ->method('splitLines')
             ->will($this->returnValue(array('  test_master     edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior')));
 
-        $process->expects($this->at(5))
+        $process->expects($this->at(6))
             ->method('execute')
             ->with($this->stringContains('git branch --no-color'));
 
-        $process->expects($this->at(6))
+        $process->expects($this->at(7))
             ->method('splitLines')
             ->will($this->returnValue(array('* test_master')));