Page MenuHomePhabricator

D15482.id37308.diff
No OneTemporary

D15482.id37308.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -633,6 +633,8 @@
'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php',
'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php',
'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php',
+ 'DiffusionGitLFSAuthenticateWorkflow' => 'applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php',
+ 'DiffusionGitLFSTemporaryTokenType' => 'applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php',
'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php',
'DiffusionGitReceivePackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php',
'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php',
@@ -4760,6 +4762,8 @@
'DiffusionGitBranch' => 'Phobject',
'DiffusionGitBranchTestCase' => 'PhabricatorTestCase',
'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
+ 'DiffusionGitLFSAuthenticateWorkflow' => 'DiffusionGitSSHWorkflow',
+ 'DiffusionGitLFSTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionGitReceivePackSSHWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionGitRequest' => 'DiffusionRequest',
diff --git a/src/applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php b/src/applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php
@@ -0,0 +1,118 @@
+<?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;
+ }
+
+}
diff --git a/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php b/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php
@@ -0,0 +1,18 @@
+<?php
+
+final class DiffusionGitLFSTemporaryTokenType
+ extends PhabricatorAuthTemporaryTokenType {
+
+ const TOKENTYPE = 'diffusion.git.lfs';
+ const HTTP_USERNAME = '@git-lfs';
+
+ public function getTokenTypeDisplayName() {
+ return pht('Git Large File Storage');
+ }
+
+ public function getTokenReadableTypeName(
+ PhabricatorAuthTemporaryToken $token) {
+ return pht('Git LFS Token');
+ }
+
+}
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1518,6 +1518,10 @@
return null;
}
+ return $this->getRawHTTPCloneURIObject();
+ }
+
+ private function getRawHTTPCloneURIObject() {
$uri = PhabricatorEnv::getProductionURI($this->getURI());
$uri = new PhutilURI($uri);
@@ -1819,6 +1823,38 @@
return !$this->isSVN();
}
+ public function canUseGitLFS() {
+ if (!$this->isGit()) {
+ return false;
+ }
+
+ if (!$this->isHosted()) {
+ return false;
+ }
+
+ // TODO: Unprototype this feature.
+ if (!PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function getGitLFSURI($path = null) {
+ if (!$this->canUseGitLFS()) {
+ throw new Exception(
+ pht(
+ 'This repository does not support Git LFS, so Git LFS URIs can '.
+ 'not be generated for it.'));
+ }
+
+ $uri = $this->getRawHTTPCloneURIObject();
+ $uri = (string)$uri;
+ $uri = $uri.'/'.$path;
+
+ return $uri;
+ }
+
public function canMirror() {
if ($this->isGit() || $this->isHg()) {
return true;

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 2, 6:52 AM (5 d, 17 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7390389
Default Alt Text
D15482.id37308.diff (7 KB)

Event Timeline