Differential D15482 Diff 37308 src/applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php
- This file was added.
| <?php | |||||
| final class DiffusionGitLFSAuthenticateWorkflow | |||||
| extends DiffusionGitSSHWorkflow { | |||||
| protected function didConstruct() { | |||||
| $this->setName('git-lfs-authenticate'); | |||||
| $this->setArguments( | |||||
| array( | |||||
| array( | |||||
| 'name' => 'argv', | |||||
| 'wildcard' => true, | |||||
| ), | |||||
| )); | |||||
| } | |||||
| protected function identifyRepository() { | |||||
| return $this->loadRepositoryWithPath($this->getLFSPathArgument()); | |||||
| } | |||||
| private function getLFSPathArgument() { | |||||
| return $this->getLFSArgument(0); | |||||
| } | |||||
| private function getLFSOperationArgument() { | |||||
| return $this->getLFSArgument(1); | |||||
| } | |||||
| private function getLFSArgument($position) { | |||||
| $args = $this->getArgs(); | |||||
| $argv = $args->getArg('argv'); | |||||
| if (!isset($argv[$position])) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Expected `git-lfs-authenticate <path> <operation>`, but received '. | |||||
| 'too few arguments.')); | |||||
| } | |||||
| return $argv[$position]; | |||||
| } | |||||
| protected function executeRepositoryOperations() { | |||||
| $operation = $this->getLFSOperationArgument(); | |||||
| // NOTE: We aren't checking write access here, even for "upload". The | |||||
| // HTTP endpoint should be able to do that for us. | |||||
| switch ($operation) { | |||||
| case 'upload': | |||||
| case 'download': | |||||
| break; | |||||
| default: | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Git LFS operation "%s" is not supported by this server.', | |||||
| $operation)); | |||||
| } | |||||
| $repository = $this->getRepository(); | |||||
| if (!$repository->isGit()) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Repository "%s" is not a Git repository. Git LFS is only '. | |||||
| 'supported for Git repositories.', | |||||
| $repository->getDisplayName())); | |||||
| } | |||||
| if (!$repository->canUseGitLFS()) { | |||||
| throw new Exception( | |||||
| pht('Git LFS is not enabled for this repository.')); | |||||
| } | |||||
| // NOTE: This is usually the same as the default URI (which does not | |||||
| // need to be specified in the response), but the protocol or domain may | |||||
| // differ in some situations. | |||||
| $lfs_uri = $repository->getGitLFSURI('info/lfs'); | |||||
| // Generate a temporary token to allow the user to acces LFS over HTTP. | |||||
| // This works even if normal HTTP repository operations are not available | |||||
| // on this host, and does not require the user to have a VCS password. | |||||
| $user = $this->getUser(); | |||||
| $headers = array(); | |||||
| $lfs_user = DiffusionGitLFSTemporaryTokenType::HTTP_USERNAME; | |||||
| $lfs_pass = Filesystem::readRandomCharacters(32); | |||||
| $lfs_hash = PhabricatorHash::digest($lfs_pass); | |||||
| $ttl = PhabricatorTime::getNow() + phutil_units('1 day in seconds'); | |||||
| $token = id(new PhabricatorAuthTemporaryToken()) | |||||
| ->setTokenResource($repository->getPHID()) | |||||
| ->setTokenType(DiffusionGitLFSTemporaryTokenType::TOKENTYPE) | |||||
| ->setTokenCode($lfs_hash) | |||||
| ->setUserPHID($user->getPHID()) | |||||
| ->setTemporaryTokenProperty('lfs.operation', $operation) | |||||
| ->setTokenExpires($ttl) | |||||
| ->save(); | |||||
| $authorization_header = base64_encode($lfs_user.':'.$lfs_pass); | |||||
| $headers['Authorization'] = 'Basic '.$authorization_header; | |||||
| $result = array( | |||||
| 'header' => $headers, | |||||
| 'href' => $lfs_uri, | |||||
| ); | |||||
| $result = phutil_json_encode($result); | |||||
| $this->writeIO($result); | |||||
| $this->waitForGitClient(); | |||||
| return 0; | |||||
| } | |||||
| } | |||||