@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement "git-lfs-authenticate" over SSH

Summary:
Ref T7789. This implements a (probably) usable "git-lfs-authenticate" on top of the new temporary token infrastructure.

This won't actually do anything yet, since nothing reads the tokens.

Test Plan:
```
$ ./bin/ssh-exec --phabricator-ssh-user admin --ssh-command 'git-lfs-authenticate'
phabricator-ssh-exec: Expected `git-lfs-authenticate <path> <operation>`, but received too few arguments.
```

```
$ ./bin/ssh-exec --phabricator-ssh-user admin --ssh-command 'git-lfs-authenticate x'
phabricator-ssh-exec: Unrecognized repository path "x". Expected a path like "/diffusion/X/" or "/diffusion/123/".
```

```
$ ./bin/ssh-exec --phabricator-ssh-user admin --ssh-command 'git-lfs-authenticate diffusion/22'
Exception: Expected `git-lfs-authenticate <path> <operation>`, but received too few arguments.
```

```
$ ./bin/ssh-exec --phabricator-ssh-user admin --ssh-command 'git-lfs-authenticate diffusion/22 y'
Exception: Git LFS operation "y" is not supported by this server.
```

```
$ ./bin/ssh-exec --phabricator-ssh-user admin --ssh-command 'git-lfs-authenticate diffusion/22 upload'
{"header":{"Authorization":"Basic QGdpdC1sZnM6NmR2bDVreWVsaXNuMmtnNXBtbnZwM3VlaWhubmI1bmI="},"href":"http:\/\/local.phacility.com\/diffusion\/22\/new-callsign-free-repository.git\/info\/lfs"}
```

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T7789

Differential Revision: https://secure.phabricator.com/D15482

+176
+4
src/__phutil_library_map__.php
··· 633 633 'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php', 634 634 'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php', 635 635 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php', 636 + 'DiffusionGitLFSAuthenticateWorkflow' => 'applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php', 637 + 'DiffusionGitLFSTemporaryTokenType' => 'applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php', 636 638 'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php', 637 639 'DiffusionGitReceivePackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitReceivePackSSHWorkflow.php', 638 640 'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php', ··· 4760 4762 'DiffusionGitBranch' => 'Phobject', 4761 4763 'DiffusionGitBranchTestCase' => 'PhabricatorTestCase', 4762 4764 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 4765 + 'DiffusionGitLFSAuthenticateWorkflow' => 'DiffusionGitSSHWorkflow', 4766 + 'DiffusionGitLFSTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType', 4763 4767 'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery', 4764 4768 'DiffusionGitReceivePackSSHWorkflow' => 'DiffusionGitSSHWorkflow', 4765 4769 'DiffusionGitRequest' => 'DiffusionRequest',
+118
src/applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php
··· 1 + <?php 2 + 3 + final class DiffusionGitLFSAuthenticateWorkflow 4 + extends DiffusionGitSSHWorkflow { 5 + 6 + protected function didConstruct() { 7 + $this->setName('git-lfs-authenticate'); 8 + $this->setArguments( 9 + array( 10 + array( 11 + 'name' => 'argv', 12 + 'wildcard' => true, 13 + ), 14 + )); 15 + } 16 + 17 + protected function identifyRepository() { 18 + return $this->loadRepositoryWithPath($this->getLFSPathArgument()); 19 + } 20 + 21 + private function getLFSPathArgument() { 22 + return $this->getLFSArgument(0); 23 + } 24 + 25 + private function getLFSOperationArgument() { 26 + return $this->getLFSArgument(1); 27 + } 28 + 29 + private function getLFSArgument($position) { 30 + $args = $this->getArgs(); 31 + $argv = $args->getArg('argv'); 32 + 33 + if (!isset($argv[$position])) { 34 + throw new Exception( 35 + pht( 36 + 'Expected `git-lfs-authenticate <path> <operation>`, but received '. 37 + 'too few arguments.')); 38 + } 39 + 40 + return $argv[$position]; 41 + } 42 + 43 + protected function executeRepositoryOperations() { 44 + $operation = $this->getLFSOperationArgument(); 45 + 46 + // NOTE: We aren't checking write access here, even for "upload". The 47 + // HTTP endpoint should be able to do that for us. 48 + 49 + switch ($operation) { 50 + case 'upload': 51 + case 'download': 52 + break; 53 + default: 54 + throw new Exception( 55 + pht( 56 + 'Git LFS operation "%s" is not supported by this server.', 57 + $operation)); 58 + } 59 + 60 + $repository = $this->getRepository(); 61 + 62 + if (!$repository->isGit()) { 63 + throw new Exception( 64 + pht( 65 + 'Repository "%s" is not a Git repository. Git LFS is only '. 66 + 'supported for Git repositories.', 67 + $repository->getDisplayName())); 68 + } 69 + 70 + if (!$repository->canUseGitLFS()) { 71 + throw new Exception( 72 + pht('Git LFS is not enabled for this repository.')); 73 + } 74 + 75 + // NOTE: This is usually the same as the default URI (which does not 76 + // need to be specified in the response), but the protocol or domain may 77 + // differ in some situations. 78 + 79 + $lfs_uri = $repository->getGitLFSURI('info/lfs'); 80 + 81 + // Generate a temporary token to allow the user to acces LFS over HTTP. 82 + // This works even if normal HTTP repository operations are not available 83 + // on this host, and does not require the user to have a VCS password. 84 + 85 + $user = $this->getUser(); 86 + $headers = array(); 87 + 88 + $lfs_user = DiffusionGitLFSTemporaryTokenType::HTTP_USERNAME; 89 + $lfs_pass = Filesystem::readRandomCharacters(32); 90 + $lfs_hash = PhabricatorHash::digest($lfs_pass); 91 + 92 + $ttl = PhabricatorTime::getNow() + phutil_units('1 day in seconds'); 93 + 94 + $token = id(new PhabricatorAuthTemporaryToken()) 95 + ->setTokenResource($repository->getPHID()) 96 + ->setTokenType(DiffusionGitLFSTemporaryTokenType::TOKENTYPE) 97 + ->setTokenCode($lfs_hash) 98 + ->setUserPHID($user->getPHID()) 99 + ->setTemporaryTokenProperty('lfs.operation', $operation) 100 + ->setTokenExpires($ttl) 101 + ->save(); 102 + 103 + $authorization_header = base64_encode($lfs_user.':'.$lfs_pass); 104 + $headers['Authorization'] = 'Basic '.$authorization_header; 105 + 106 + $result = array( 107 + 'header' => $headers, 108 + 'href' => $lfs_uri, 109 + ); 110 + $result = phutil_json_encode($result); 111 + 112 + $this->writeIO($result); 113 + $this->waitForGitClient(); 114 + 115 + return 0; 116 + } 117 + 118 + }
+18
src/applications/diffusion/gitlfs/DiffusionGitLFSTemporaryTokenType.php
··· 1 + <?php 2 + 3 + final class DiffusionGitLFSTemporaryTokenType 4 + extends PhabricatorAuthTemporaryTokenType { 5 + 6 + const TOKENTYPE = 'diffusion.git.lfs'; 7 + const HTTP_USERNAME = '@git-lfs'; 8 + 9 + public function getTokenTypeDisplayName() { 10 + return pht('Git Large File Storage'); 11 + } 12 + 13 + public function getTokenReadableTypeName( 14 + PhabricatorAuthTemporaryToken $token) { 15 + return pht('Git LFS Token'); 16 + } 17 + 18 + }
+36
src/applications/repository/storage/PhabricatorRepository.php
··· 1518 1518 return null; 1519 1519 } 1520 1520 1521 + return $this->getRawHTTPCloneURIObject(); 1522 + } 1523 + 1524 + private function getRawHTTPCloneURIObject() { 1521 1525 $uri = PhabricatorEnv::getProductionURI($this->getURI()); 1522 1526 $uri = new PhutilURI($uri); 1523 1527 ··· 1817 1821 1818 1822 public function canUsePathTree() { 1819 1823 return !$this->isSVN(); 1824 + } 1825 + 1826 + public function canUseGitLFS() { 1827 + if (!$this->isGit()) { 1828 + return false; 1829 + } 1830 + 1831 + if (!$this->isHosted()) { 1832 + return false; 1833 + } 1834 + 1835 + // TODO: Unprototype this feature. 1836 + if (!PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) { 1837 + return false; 1838 + } 1839 + 1840 + return true; 1841 + } 1842 + 1843 + public function getGitLFSURI($path = null) { 1844 + if (!$this->canUseGitLFS()) { 1845 + throw new Exception( 1846 + pht( 1847 + 'This repository does not support Git LFS, so Git LFS URIs can '. 1848 + 'not be generated for it.')); 1849 + } 1850 + 1851 + $uri = $this->getRawHTTPCloneURIObject(); 1852 + $uri = (string)$uri; 1853 + $uri = $uri.'/'.$path; 1854 + 1855 + return $uri; 1820 1856 } 1821 1857 1822 1858 public function canMirror() {