@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
3abstract class PhabricatorSSHWorkflow
4 extends PhutilArgumentWorkflow {
5
6 // NOTE: We are explicitly extending "PhutilArgumentWorkflow", not
7 // "PhabricatorManagementWorkflow". We want to avoid inheriting "getViewer()"
8 // and other methods which assume workflows are administrative commands
9 // like `bin/storage`.
10
11 private $sshUser;
12 private $iochannel;
13 private $errorChannel;
14 private $isClusterRequest;
15 private $originalArguments;
16 private $requestIdentifier;
17
18 public function isExecutable() {
19 return false;
20 }
21
22 public function setErrorChannel(PhutilChannel $error_channel) {
23 $this->errorChannel = $error_channel;
24 return $this;
25 }
26
27 public function getErrorChannel() {
28 return $this->errorChannel;
29 }
30
31 public function setSSHUser(PhabricatorUser $ssh_user) {
32 $this->sshUser = $ssh_user;
33 return $this;
34 }
35
36 public function getSSHUser() {
37 return $this->sshUser;
38 }
39
40 public function setIOChannel(PhutilChannel $channel) {
41 $this->iochannel = $channel;
42 return $this;
43 }
44
45 public function getIOChannel() {
46 return $this->iochannel;
47 }
48
49 public function readAllInput() {
50 $channel = $this->getIOChannel();
51 while ($channel->update()) {
52 PhutilChannel::waitForAny(array($channel));
53 if (!$channel->isOpenForReading()) {
54 break;
55 }
56 }
57 return $channel->read();
58 }
59
60 public function writeIO($data) {
61 $this->getIOChannel()->write($data);
62 return $this;
63 }
64
65 public function writeErrorIO($data) {
66 $this->getErrorChannel()->write($data);
67 return $this;
68 }
69
70 protected function newPassthruCommand() {
71 return id(new PhabricatorSSHPassthruCommand())
72 ->setErrorChannel($this->getErrorChannel());
73 }
74
75 public function setIsClusterRequest($is_cluster_request) {
76 $this->isClusterRequest = $is_cluster_request;
77 return $this;
78 }
79
80 public function getIsClusterRequest() {
81 return $this->isClusterRequest;
82 }
83
84 public function setOriginalArguments(array $original_arguments) {
85 $this->originalArguments = $original_arguments;
86 return $this;
87 }
88
89 public function getOriginalArguments() {
90 return $this->originalArguments;
91 }
92
93 public function setRequestIdentifier($request_identifier) {
94 $this->requestIdentifier = $request_identifier;
95 return $this;
96 }
97
98 public function getRequestIdentifier() {
99 return $this->requestIdentifier;
100 }
101
102 public function getSSHRemoteAddress() {
103 $ssh_client = getenv('SSH_CLIENT');
104 if (!$ssh_client || !strlen($ssh_client)) {
105 return null;
106 }
107
108 // TODO: When commands are proxied, the original remote address should
109 // also be proxied.
110
111 // This has the format "<ip> <remote-port> <local-port>". Grab the IP.
112 $remote_address = head(explode(' ', $ssh_client));
113
114 try {
115 $address = PhutilIPAddress::newAddress($remote_address);
116 } catch (Exception $ex) {
117 return null;
118 }
119
120 return $address->getAddress();
121 }
122
123}