Changeset View
Changeset View
Standalone View
Standalone View
src/applications/diffusion/controller/DiffusionServeController.php
| <?php | <?php | ||||
| final class DiffusionServeController extends DiffusionController { | final class DiffusionServeController extends DiffusionController { | ||||
| private $serviceViewer; | private $serviceViewer; | ||||
| private $serviceRepository; | private $serviceRepository; | ||||
| private $isGitLFSRequest; | private $isGitLFSRequest; | ||||
| private $gitLFSToken; | private $gitLFSToken; | ||||
| private $gitLFSInput; | |||||
| public function setServiceViewer(PhabricatorUser $viewer) { | public function setServiceViewer(PhabricatorUser $viewer) { | ||||
| $this->getRequest()->setUser($viewer); | $this->getRequest()->setUser($viewer); | ||||
| $this->serviceViewer = $viewer; | $this->serviceViewer = $viewer; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 261 Lines • ▼ Show 20 Lines | private function serveRequest(AphrontRequest $request) { | ||||
| if ($is_push) { | if ($is_push) { | ||||
| $can_push = PhabricatorPolicyFilter::hasCapability( | $can_push = PhabricatorPolicyFilter::hasCapability( | ||||
| $viewer, | $viewer, | ||||
| $repository, | $repository, | ||||
| DiffusionPushCapability::CAPABILITY); | DiffusionPushCapability::CAPABILITY); | ||||
| if (!$can_push) { | if (!$can_push) { | ||||
| if ($viewer->isLoggedIn()) { | if ($viewer->isLoggedIn()) { | ||||
| $error_code = 403; | |||||
| $error_message = pht( | |||||
| 'You do not have permission to push to this repository ("%s").', | |||||
| $repository->getDisplayName()); | |||||
| if ($this->getIsGitLFSRequest()) { | |||||
| return DiffusionGitLFSResponse::newErrorResponse( | |||||
| $error_code, | |||||
| $error_message); | |||||
| } else { | |||||
| return new PhabricatorVCSResponse( | return new PhabricatorVCSResponse( | ||||
| 403, | $error_code, | ||||
| pht( | $error_message); | ||||
| 'You do not have permission to push to this '. | } | ||||
| 'repository.')); | |||||
| } else { | } else { | ||||
| if ($allow_auth) { | if ($allow_auth) { | ||||
| return new PhabricatorVCSResponse( | return new PhabricatorVCSResponse( | ||||
| 401, | 401, | ||||
| pht('You must log in to push to this repository.')); | pht('You must log in to push to this repository.')); | ||||
| } else { | } else { | ||||
| return new PhabricatorVCSResponse( | return new PhabricatorVCSResponse( | ||||
| 403, | 403, | ||||
| ▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | final class DiffusionServeController extends DiffusionController { | ||||
| private function isReadOnlyRequest( | private function isReadOnlyRequest( | ||||
| PhabricatorRepository $repository) { | PhabricatorRepository $repository) { | ||||
| $request = $this->getRequest(); | $request = $this->getRequest(); | ||||
| $method = $_SERVER['REQUEST_METHOD']; | $method = $_SERVER['REQUEST_METHOD']; | ||||
| // TODO: This implementation is safe by default, but very incomplete. | // TODO: This implementation is safe by default, but very incomplete. | ||||
| // TODO: This doesn't get the right result for Git LFS yet. | if ($this->getIsGitLFSRequest()) { | ||||
| return $this->isGitLFSReadOnlyRequest($repository); | |||||
| } | |||||
| switch ($repository->getVersionControlSystem()) { | switch ($repository->getVersionControlSystem()) { | ||||
| case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: | case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: | ||||
| $service = $request->getStr('service'); | $service = $request->getStr('service'); | ||||
| $path = $this->getRequestDirectoryPath($repository); | $path = $this->getRequestDirectoryPath($repository); | ||||
| // NOTE: Service names are the reverse of what you might expect, as they | // NOTE: Service names are the reverse of what you might expect, as they | ||||
| // are from the point of view of the server. The main read service is | // are from the point of view of the server. The main read service is | ||||
| // "git-upload-pack", and the main write service is "git-receive-pack". | // "git-upload-pack", and the main write service is "git-receive-pack". | ||||
| ▲ Show 20 Lines • Show All 472 Lines • ▼ Show 20 Lines | if (preg_match('(^upload/(.*)\z)', $path, $matches)) { | ||||
| $path)); | $path)); | ||||
| } | } | ||||
| } | } | ||||
| private function serveGitLFSBatchRequest( | private function serveGitLFSBatchRequest( | ||||
| PhabricatorRepository $repository, | PhabricatorRepository $repository, | ||||
| PhabricatorUser $viewer) { | PhabricatorUser $viewer) { | ||||
| $input = PhabricatorStartup::getRawInput(); | $input = $this->getGitLFSInput(); | ||||
| $input = phutil_json_decode($input); | |||||
| $operation = idx($input, 'operation'); | $operation = idx($input, 'operation'); | ||||
| switch ($operation) { | switch ($operation) { | ||||
| case 'upload': | case 'upload': | ||||
| $want_upload = true; | $want_upload = true; | ||||
| break; | break; | ||||
| case 'download': | case 'download': | ||||
| $want_upload = false; | $want_upload = false; | ||||
| ▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | private function getGitLFSRequestPath(PhabricatorRepository $repository) { | ||||
| $matches = null; | $matches = null; | ||||
| if (preg_match('(^/info/lfs(?:\z|/)(.*))', $request_path, $matches)) { | if (preg_match('(^/info/lfs(?:\z|/)(.*))', $request_path, $matches)) { | ||||
| return $matches[1]; | return $matches[1]; | ||||
| } | } | ||||
| return null; | return null; | ||||
| } | } | ||||
| private function getGitLFSInput() { | |||||
| if (!$this->gitLFSInput) { | |||||
| $input = PhabricatorStartup::getRawInput(); | |||||
| $input = phutil_json_decode($input); | |||||
| $this->gitLFSInput = $input; | |||||
| } | |||||
| return $this->gitLFSInput; | |||||
| } | |||||
| private function isGitLFSReadOnlyRequest(PhabricatorRepository $repository) { | |||||
| if (!$this->getIsGitLFSRequest()) { | |||||
| return false; | |||||
| } | |||||
| $path = $this->getGitLFSRequestPath($repository); | |||||
| if ($path === 'objects/batch') { | |||||
| $input = $this->getGitLFSInput(); | |||||
| $operation = idx($input, 'operation'); | |||||
| switch ($operation) { | |||||
| case 'download': | |||||
| return true; | |||||
| default: | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| } | } | ||||