@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<?php
2
3final class DrydockSFTPFilesystemInterface extends DrydockFilesystemInterface {
4
5 private $passphraseSSHKey;
6
7 private function openCredentialsIfNotOpen() {
8 if ($this->passphraseSSHKey !== null) {
9 return;
10 }
11
12 $credential = id(new PassphraseCredentialQuery())
13 ->setViewer(PhabricatorUser::getOmnipotentUser())
14 ->withIDs(array($this->getConfig('credential')))
15 ->needSecrets(true)
16 ->executeOne();
17
18 if ($credential->getProvidesType() !==
19 PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) {
20 throw new Exception(pht('Only private key credentials are supported.'));
21 }
22
23 $this->passphraseSSHKey = PassphraseSSHKey::loadFromPHID(
24 $credential->getPHID(),
25 PhabricatorUser::getOmnipotentUser());
26 }
27
28 private function getExecFuture($path) {
29 $this->openCredentialsIfNotOpen();
30
31 return new ExecFuture(
32 'sftp -o "StrictHostKeyChecking no" -P %s -i %P %P@%s',
33 $this->getConfig('port'),
34 $this->passphraseSSHKey->getKeyfileEnvelope(),
35 $this->passphraseSSHKey->getUsernameEnvelope(),
36 $this->getConfig('host'));
37 }
38
39 public function readFile($path) {
40 $target = new TempFile();
41 $future = $this->getExecFuture($path);
42 $future->write(csprintf('get %s %s', $path, $target));
43 $future->resolvex();
44 return Filesystem::readFile($target);
45 }
46
47 public function saveFile($path, $name) {
48 $data = $this->readFile($path);
49 $file = PhabricatorFile::newFromFileData(
50 $data,
51 array('name' => $name));
52 $file->setName($name);
53 $file->save();
54 return $file;
55 }
56
57 public function writeFile($path, $data) {
58 $source = new TempFile();
59 Filesystem::writeFile($source, $data);
60 $future = $this->getExecFuture($path);
61 $future->write(csprintf('put %s %s', $source, $path));
62 $future->resolvex();
63 }
64
65}