@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.

Fill in new URI credential edit web UI interfaces

Summary:
Ref T10748. Ref T10366. Allows users to set credential for new URIs.

- Ref T7221. Our handling of the "git://" protocol is currently incorrect. This protocol is not authenticated, but is considered an SSH protocol. In the new UI, it is considered an anonymous/unauthenticated protocol instead.
- Ref T10241. This fixes the `PassphraseCredentialControl` so it doesn't silently edit the value if the current value is not visible to you and/or not valid.

Test Plan:
Performed a whole lot of credential edits, removals, and adjustments. I'll give this additional vetting before cutting over to it.

{F1253207}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T7221, T10241, T10366, T10748

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

+551 -24
+2
src/__phutil_library_map__.php
··· 789 789 'DiffusionRepositorySymbolsManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php', 790 790 'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php', 791 791 'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php', 792 + 'DiffusionRepositoryURICredentialController' => 'applications/diffusion/controller/DiffusionRepositoryURICredentialController.php', 792 793 'DiffusionRepositoryURIDisableController' => 'applications/diffusion/controller/DiffusionRepositoryURIDisableController.php', 793 794 'DiffusionRepositoryURIEditController' => 'applications/diffusion/controller/DiffusionRepositoryURIEditController.php', 794 795 'DiffusionRepositoryURIViewController' => 'applications/diffusion/controller/DiffusionRepositoryURIViewController.php', ··· 5020 5021 'DiffusionRepositorySymbolsManagementPanel' => 'DiffusionRepositoryManagementPanel', 5021 5022 'DiffusionRepositoryTag' => 'Phobject', 5022 5023 'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController', 5024 + 'DiffusionRepositoryURICredentialController' => 'DiffusionController', 5023 5025 'DiffusionRepositoryURIDisableController' => 'DiffusionController', 5024 5026 'DiffusionRepositoryURIEditController' => 'DiffusionController', 5025 5027 'DiffusionRepositoryURIViewController' => 'DiffusionController',
+2
src/applications/diffusion/application/PhabricatorDiffusionApplication.php
··· 97 97 => 'DiffusionRepositoryURIDisableController', 98 98 $this->getEditRoutePattern('edit/') 99 99 => 'DiffusionRepositoryURIEditController', 100 + 'credential/(?P<id>[0-9]\d*)/(?P<action>edit|remove)/' 101 + => 'DiffusionRepositoryURICredentialController', 100 102 ), 101 103 'edit/' => array( 102 104 '' => 'DiffusionRepositoryEditMainController',
+1 -1
src/applications/diffusion/controller/DiffusionMirrorEditController.php
··· 108 108 ->setName('remoteURI') 109 109 ->setValue($v_remote) 110 110 ->setError($e_remote)) 111 - ->appendChild( 111 + ->appendControl( 112 112 id(new PassphraseCredentialControl()) 113 113 ->setLabel(pht('Credentials')) 114 114 ->setName('credential')
+1
src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
··· 510 510 ->setAdjustFormPageCallback(array($this, 'adjustAuthPage')) 511 511 ->addControl( 512 512 id(new PassphraseCredentialControl()) 513 + ->setViewer($this->getViewer()) 513 514 ->setName('credential')); 514 515 } 515 516
+159
src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php
··· 1 + <?php 2 + 3 + final class DiffusionRepositoryURICredentialController 4 + extends DiffusionController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $response = $this->loadDiffusionContextForEdit(); 8 + if ($response) { 9 + return $response; 10 + } 11 + 12 + $viewer = $this->getViewer(); 13 + $drequest = $this->getDiffusionRequest(); 14 + $repository = $drequest->getRepository(); 15 + 16 + $id = $request->getURIData('id'); 17 + $uri = id(new PhabricatorRepositoryURIQuery()) 18 + ->setViewer($viewer) 19 + ->withIDs(array($id)) 20 + ->withRepositories(array($repository)) 21 + ->requireCapabilities( 22 + array( 23 + PhabricatorPolicyCapability::CAN_VIEW, 24 + PhabricatorPolicyCapability::CAN_EDIT, 25 + )) 26 + ->executeOne(); 27 + if (!$uri) { 28 + return new Aphront404Response(); 29 + } 30 + 31 + $is_builtin = $uri->isBuiltin(); 32 + $has_credential = (bool)$uri->getCredentialPHID(); 33 + $view_uri = $uri->getViewURI(); 34 + $is_remove = ($request->getURIData('action') == 'remove'); 35 + 36 + if ($is_builtin) { 37 + return $this->newDialog() 38 + ->setTitle(pht('Builtin URIs Do Not Use Credentials')) 39 + ->appendParagraph( 40 + pht( 41 + 'You can not set a credential for builtin URIs which Phabricator '. 42 + 'hosts and serves. Phabricator does not fetch from these URIs or '. 43 + 'push to these URIs, and does not need credentials to '. 44 + 'authenticate any activity against them.')) 45 + ->addCancelButton($view_uri); 46 + } 47 + 48 + if ($request->isFormPost()) { 49 + $xactions = array(); 50 + 51 + if ($is_remove) { 52 + $new_phid = null; 53 + } else { 54 + $new_phid = $request->getStr('credentialPHID'); 55 + } 56 + 57 + $type_credential = PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL; 58 + 59 + $xactions[] = id(new PhabricatorRepositoryURITransaction()) 60 + ->setTransactionType($type_credential) 61 + ->setNewValue($new_phid); 62 + 63 + $editor = id(new DiffusionURIEditor()) 64 + ->setActor($viewer) 65 + ->setContinueOnNoEffect(true) 66 + ->setContinueOnMissingFields(true) 67 + ->setContentSourceFromRequest($request) 68 + ->applyTransactions($uri, $xactions); 69 + 70 + return id(new AphrontRedirectResponse())->setURI($view_uri); 71 + } 72 + 73 + $command_engine = $uri->newCommandEngine(); 74 + $is_supported = $command_engine->isCredentialSupported(); 75 + 76 + $body = null; 77 + $form = null; 78 + $width = AphrontDialogView::WIDTH_DEFAULT; 79 + if ($is_remove) { 80 + if ($has_credential) { 81 + $title = pht('Remove Credential'); 82 + $body = pht( 83 + 'This credential will no longer be used to authenticate activity '. 84 + 'against this URI.'); 85 + $button = pht('Remove Credential'); 86 + } else { 87 + $title = pht('No Credential'); 88 + $body = pht( 89 + 'This URI does not have an associated credential.'); 90 + $button = null; 91 + } 92 + } else if (!$is_supported) { 93 + $title = pht('Unauthenticated Protocol'); 94 + $body = pht( 95 + 'The protocol for this URI ("%s") does not use authentication, so '. 96 + 'you can not provide a credential.', 97 + $command_engine->getDisplayProtocol()); 98 + $button = null; 99 + } else { 100 + $effective_uri = $uri->getEffectiveURI(); 101 + 102 + $label = $command_engine->getPassphraseCredentialLabel(); 103 + $credential_type = $command_engine->getPassphraseDefaultCredentialType(); 104 + 105 + $provides_type = $command_engine->getPassphraseProvidesCredentialType(); 106 + $options = id(new PassphraseCredentialQuery()) 107 + ->setViewer($viewer) 108 + ->withIsDestroyed(false) 109 + ->withProvidesTypes(array($provides_type)) 110 + ->execute(); 111 + 112 + $control = id(new PassphraseCredentialControl()) 113 + ->setName('credentialPHID') 114 + ->setLabel($label) 115 + ->setValue($uri->getCredentialPHID()) 116 + ->setCredentialType($credential_type) 117 + ->setOptions($options); 118 + 119 + $default_user = $effective_uri->getUser(); 120 + if (strlen($default_user)) { 121 + $control->setDefaultUsername($default_user); 122 + } 123 + 124 + $form = id(new AphrontFormView()) 125 + ->setViewer($viewer) 126 + ->appendControl($control); 127 + 128 + if ($has_credential) { 129 + $title = pht('Update Credential'); 130 + $button = pht('Update Credential'); 131 + } else { 132 + $title = pht('Set Credential'); 133 + $button = pht('Set Credential'); 134 + } 135 + 136 + $width = AphrontDialogView::WIDTH_FORM; 137 + } 138 + 139 + $dialog = $this->newDialog() 140 + ->setWidth($width) 141 + ->setTitle($title) 142 + ->addCancelButton($view_uri); 143 + 144 + if ($body) { 145 + $dialog->appendParagraph($body); 146 + } 147 + 148 + if ($form) { 149 + $dialog->appendForm($form); 150 + } 151 + 152 + if ($button) { 153 + $dialog->addSubmitButton($button); 154 + } 155 + 156 + return $dialog; 157 + } 158 + 159 + }
+117 -3
src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php
··· 82 82 83 83 private function buildCurtain(PhabricatorRepositoryURI $uri) { 84 84 $viewer = $this->getViewer(); 85 + $repository = $uri->getRepository(); 85 86 $id = $uri->getID(); 86 87 87 88 $can_edit = PhabricatorPolicyFilter::hasCapability( 88 89 $viewer, 89 90 $uri, 90 91 PhabricatorPolicyCapability::CAN_EDIT); 91 - 92 92 93 93 $curtain = $this->newCurtainView($uri); 94 94 ··· 102 102 ->setWorkflow(!$can_edit) 103 103 ->setDisabled(!$can_edit)); 104 104 105 + $credential_uri = $repository->getPathURI("uri/credential/{$id}/edit/"); 106 + $remove_uri = $repository->getPathURI("uri/credential/{$id}/remove/"); 107 + $has_credential = (bool)$uri->getCredentialPHID(); 108 + 109 + if ($uri->isBuiltin()) { 110 + $can_credential = false; 111 + } else if (!$uri->newCommandEngine()->isCredentialSupported()) { 112 + $can_credential = false; 113 + } else { 114 + $can_credential = true; 115 + } 116 + 117 + $can_update = ($can_edit && $can_credential); 118 + $can_remove = ($can_edit && $has_credential); 119 + 120 + if ($has_credential) { 121 + $credential_name = pht('Update Credential'); 122 + } else { 123 + $credential_name = pht('Set Credential'); 124 + } 125 + 126 + $curtain->addAction( 127 + id(new PhabricatorActionView()) 128 + ->setIcon('fa-key') 129 + ->setName($credential_name) 130 + ->setHref($credential_uri) 131 + ->setWorkflow(true) 132 + ->setDisabled(!$can_edit)); 133 + 134 + $curtain->addAction( 135 + id(new PhabricatorActionView()) 136 + ->setIcon('fa-times') 137 + ->setName(pht('Remove Credential')) 138 + ->setHref($remove_uri) 139 + ->setWorkflow(true) 140 + ->setDisabled(!$can_remove)); 141 + 105 142 if ($uri->getIsDisabled()) { 106 143 $disable_name = pht('Enable URI'); 107 144 $disable_icon = 'fa-check'; ··· 110 147 $disable_icon = 'fa-ban'; 111 148 } 112 149 113 - $disable_uri = $uri->getRepository()->getPathURI("uri/disable/{$id}/"); 150 + $disable_uri = $repository->getPathURI("uri/disable/{$id}/"); 114 151 115 152 $curtain->addAction( 116 153 id(new PhabricatorActionView()) ··· 130 167 ->setUser($viewer); 131 168 132 169 $properties->addProperty(pht('URI'), $uri->getDisplayURI()); 133 - $properties->addProperty(pht('Credential'), 'TODO'); 170 + 171 + $credential_phid = $uri->getCredentialPHID(); 172 + $command_engine = $uri->newCommandEngine(); 173 + $is_optional = $command_engine->isCredentialOptional(); 174 + $is_supported = $command_engine->isCredentialSupported(); 175 + $is_builtin = $uri->isBuiltin(); 176 + 177 + if ($is_builtin) { 178 + $credential_icon = 'fa-circle-o'; 179 + $credential_color = 'grey'; 180 + $credential_label = pht('Builtin'); 181 + $credential_note = pht('Builtin URIs do not use credentials.'); 182 + } else if (!$is_supported) { 183 + $credential_icon = 'fa-circle-o'; 184 + $credential_color = 'grey'; 185 + $credential_label = pht('Not Supported'); 186 + $credential_note = pht('This protocol does not support authentication.'); 187 + } else if (!$credential_phid) { 188 + if ($is_optional) { 189 + $credential_icon = 'fa-circle-o'; 190 + $credential_color = 'green'; 191 + $credential_label = pht('No Credential'); 192 + $credential_note = pht('Configured for anonymous access.'); 193 + } else { 194 + $credential_icon = 'fa-times'; 195 + $credential_color = 'red'; 196 + $credential_label = pht('Required'); 197 + $credential_note = pht('Credential required but not configured.'); 198 + } 199 + } else { 200 + // Don't raise a policy exception if we can't see the credential. 201 + $credentials = id(new PassphraseCredentialQuery()) 202 + ->setViewer($viewer) 203 + ->withPHIDs(array($credential_phid)) 204 + ->execute(); 205 + $credential = head($credentials); 206 + 207 + if (!$credential) { 208 + $handles = $viewer->loadHandles(array($credential_phid)); 209 + $handle = $handles[$credential_phid]; 210 + if ($handle->getPolicyFiltered()) { 211 + $credential_icon = 'fa-lock'; 212 + $credential_color = 'grey'; 213 + $credential_label = pht('Restricted'); 214 + $credential_note = pht( 215 + 'You do not have permission to view the configured '. 216 + 'credential.'); 217 + } else { 218 + $credential_icon = 'fa-times'; 219 + $credential_color = 'red'; 220 + $credential_label = pht('Invalid'); 221 + $credential_note = pht('Configured credential is invalid.'); 222 + } 223 + } else { 224 + $provides = $credential->getProvidesType(); 225 + $needs = $command_engine->getPassphraseProvidesCredentialType(); 226 + if ($provides != $needs) { 227 + $credential_icon = 'fa-times'; 228 + $credential_color = 'red'; 229 + $credential_label = pht('Wrong Type'); 230 + } else { 231 + $credential_icon = 'fa-check'; 232 + $credential_color = 'green'; 233 + $credential_label = $command_engine->getPassphraseCredentialLabel(); 234 + } 235 + $credential_note = $viewer->renderHandle($credential_phid); 236 + } 237 + } 238 + 239 + $credential_item = id(new PHUIStatusItemView()) 240 + ->setIcon($credential_icon, $credential_color) 241 + ->setTarget(phutil_tag('strong', array(), $credential_label)) 242 + ->setNote($credential_note); 243 + 244 + $credential_view = id(new PHUIStatusListView()) 245 + ->addItem($credential_item); 246 + 247 + $properties->addProperty(pht('Credential'), $credential_view); 134 248 135 249 136 250 $io_type = $uri->getEffectiveIOType();
+11 -2
src/applications/diffusion/editor/DiffusionURIEditEngine.php
··· 83 83 protected function buildCustomEditFields($object) { 84 84 $viewer = $this->getViewer(); 85 85 86 + if ($object->isBuiltin()) { 87 + $is_builtin = true; 88 + $uri_value = (string)$object->getDisplayURI(); 89 + } else { 90 + $is_builtin = false; 91 + $uri_value = $object->getURI(); 92 + } 93 + 86 94 return array( 87 95 id(new PhabricatorHandlesEditField()) 88 96 ->setKey('repository') ··· 104 112 id(new PhabricatorTextEditField()) 105 113 ->setKey('uri') 106 114 ->setLabel(pht('URI')) 107 - ->setIsRequired(true) 108 115 ->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_URI) 109 116 ->setDescription(pht('The repository URI.')) 110 117 ->setConduitDescription(pht('Change the repository URI.')) 111 118 ->setConduitTypeDescription(pht('New repository URI.')) 112 - ->setValue($object->getURI()), 119 + ->setIsRequired(!$is_builtin) 120 + ->setIsLocked($is_builtin) 121 + ->setValue($uri_value), 113 122 id(new PhabricatorSelectEditField()) 114 123 ->setKey('io') 115 124 ->setLabel(pht('I/O Type'))
+40
src/applications/diffusion/editor/DiffusionURIEditor.php
··· 70 70 71 71 switch ($xaction->getTransactionType()) { 72 72 case PhabricatorRepositoryURITransaction::TYPE_URI: 73 + if (!$this->getIsNewObject()) { 74 + $old_uri = $object->getEffectiveURI(); 75 + } else { 76 + $old_uri = null; 77 + } 78 + 73 79 $object->setURI($xaction->getNewValue()); 80 + 81 + // If we've changed the domain or protocol of the URI, remove the 82 + // current credential. This improves behavior in several cases: 83 + 84 + // If a user switches between protocols with different credential 85 + // types, like HTTP and SSH, the old credential won't be valid anyway. 86 + // It's cleaner to remove it than leave a bad credential in place. 87 + 88 + // If a user switches hosts, the old credential is probably not 89 + // correct (and potentially confusing/misleading). Removing it forces 90 + // users to double check that they have the correct credentials. 91 + 92 + // If an attacker can't see a symmetric credential like a username and 93 + // password, they could still potentially capture it by changing the 94 + // host for a URI that uses it to `evil.com`, a server they control, 95 + // then observing the requests. Removing the credential prevents this 96 + // kind of escalation. 97 + 98 + // Since port and path changes are less likely to fall among these 99 + // cases, they don't trigger a credential wipe. 100 + 101 + $new_uri = $object->getEffectiveURI(); 102 + if ($old_uri) { 103 + $new_proto = ($old_uri->getProtocol() != $new_uri->getProtocol()); 104 + $new_domain = ($old_uri->getDomain() != $new_uri->getDomain()); 105 + if ($new_proto || $new_domain) { 106 + $object->setCredentialPHID(null); 107 + } 108 + } 74 109 break; 75 110 case PhabricatorRepositoryURITransaction::TYPE_IO: 76 111 $object->setIOType($xaction->getNewValue()); ··· 181 216 $credential_phid = $xaction->getNewValue(); 182 217 183 218 if ($credential_phid == $object->getCredentialPHID()) { 219 + continue; 220 + } 221 + 222 + // Anyone who can edit a URI can remove the credential. 223 + if ($credential_phid === null) { 184 224 continue; 185 225 } 186 226
+59 -7
src/applications/diffusion/protocol/DiffusionCommandEngine.php
··· 57 57 return $this->protocol; 58 58 } 59 59 60 + public function getDisplayProtocol() { 61 + return $this->getProtocol().'://'; 62 + } 63 + 60 64 public function setCredentialPHID($credential_phid) { 61 65 $this->credentialPHID = $credential_phid; 62 66 return $this; ··· 197 201 return $env; 198 202 } 199 203 200 - protected function isSSHProtocol() { 204 + public function isSSHProtocol() { 201 205 return ($this->getProtocol() == 'ssh'); 202 206 } 203 207 204 - protected function isSVNProtocol() { 208 + public function isSVNProtocol() { 205 209 return ($this->getProtocol() == 'svn'); 206 210 } 207 211 208 - protected function isSVNSSHProtocol() { 212 + public function isSVNSSHProtocol() { 209 213 return ($this->getProtocol() == 'svn+ssh'); 210 214 } 211 215 212 - protected function isHTTPProtocol() { 216 + public function isHTTPProtocol() { 213 217 return ($this->getProtocol() == 'http'); 214 218 } 215 219 216 - protected function isHTTPSProtocol() { 220 + public function isHTTPSProtocol() { 217 221 return ($this->getProtocol() == 'https'); 218 222 } 219 223 220 - protected function isAnyHTTPProtocol() { 224 + public function isAnyHTTPProtocol() { 221 225 return ($this->isHTTPProtocol() || $this->isHTTPSProtocol()); 222 226 } 223 227 224 - protected function isAnySSHProtocol() { 228 + public function isAnySSHProtocol() { 225 229 return ($this->isSSHProtocol() || $this->isSVNSSHProtocol()); 230 + } 231 + 232 + public function isCredentialSupported() { 233 + return ($this->getPassphraseProvidesCredentialType() !== null); 234 + } 235 + 236 + public function isCredentialOptional() { 237 + if ($this->isAnySSHProtocol()) { 238 + return false; 239 + } 240 + 241 + return true; 242 + } 243 + 244 + public function getPassphraseCredentialLabel() { 245 + if ($this->isAnySSHProtocol()) { 246 + return pht('SSH Key'); 247 + } 248 + 249 + if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) { 250 + return pht('Password'); 251 + } 252 + 253 + return null; 254 + } 255 + 256 + public function getPassphraseDefaultCredentialType() { 257 + if ($this->isAnySSHProtocol()) { 258 + return PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE; 259 + } 260 + 261 + if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) { 262 + return PassphrasePasswordCredentialType::CREDENTIAL_TYPE; 263 + } 264 + 265 + return null; 266 + } 267 + 268 + public function getPassphraseProvidesCredentialType() { 269 + if ($this->isAnySSHProtocol()) { 270 + return PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE; 271 + } 272 + 273 + if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) { 274 + return PassphrasePasswordCredentialType::PROVIDES_TYPE; 275 + } 276 + 277 + return null; 226 278 } 227 279 228 280 protected function getSSHWrapper() {
+41 -1
src/applications/passphrase/view/PassphraseCredentialControl.php
··· 42 42 foreach ($this->options as $option) { 43 43 $options_map[$option->getPHID()] = pht( 44 44 '%s %s', 45 - 'K'.$option->getID(), 45 + $option->getMonogram(), 46 46 $option->getName()); 47 47 } 48 + 49 + // The user editing the form may not have permission to see the current 50 + // credential. Populate it into the menu to allow them to save the form 51 + // without making any changes. 52 + $current_phid = $this->getValue(); 53 + if (strlen($current_phid) && empty($options_map[$current_phid])) { 54 + $viewer = $this->getViewer(); 55 + 56 + $user_credential = id(new PassphraseCredentialQuery()) 57 + ->setViewer($viewer) 58 + ->withPHIDs(array($current_phid)) 59 + ->executeOne(); 60 + if (!$user_credential) { 61 + // Pull the credential with the ominipotent viewer so we can look up 62 + // the ID and tell if it's restricted or invalid. 63 + $omnipotent_credential = id(new PassphraseCredentialQuery()) 64 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 65 + ->withPHIDs(array($current_phid)) 66 + ->executeOne(); 67 + if ($omnipotent_credential) { 68 + $current_name = pht( 69 + '%s (Restricted Credential)', 70 + $omnipotent_credential->getMonogram()); 71 + } else { 72 + $current_name = pht( 73 + 'Invalid Credential ("%s")', 74 + $current_phid); 75 + } 76 + } else { 77 + $current_name = pht( 78 + '%s %s', 79 + $user_credential->getMonogram(), 80 + $user_credential->getName()); 81 + } 82 + 83 + $options_map = array( 84 + $current_phid => $current_name, 85 + ) + $options_map; 86 + } 87 + 48 88 49 89 $disabled = $this->getDisabled(); 50 90 if ($this->allowNull) {
+79 -10
src/applications/repository/storage/PhabricatorRepositoryURI.php
··· 193 193 194 194 195 195 public function getDisplayURI() { 196 - $uri = new PhutilURI($this->getURI()); 196 + return $this->getURIObject(false); 197 + } 198 + 199 + public function getEffectiveURI() { 200 + return $this->getURIObject(true); 201 + } 202 + 203 + private function getURIObject($normalize) { 204 + // Users can provide Git/SCP-style URIs in the form "user@host:path". 205 + // These are equivalent to "ssh://user@host/path". We use the more standard 206 + // form internally, and convert to it if we need to specify a port number, 207 + // but try to preserve what the user typed when displaying the URI. 197 208 198 - $protocol = $this->getForcedProtocol(); 199 - if ($protocol) { 200 - $uri->setProtocol($protocol); 209 + if ($this->isBuiltin()) { 210 + $builtin_protocol = $this->getForcedProtocol(); 211 + $builtin_domain = $this->getForcedHost(); 212 + $raw_uri = "{$builtin_protocol}://{$builtin_domain}"; 213 + } else { 214 + $raw_uri = $this->getURI(); 215 + } 216 + 217 + $port = $this->getForcedPort(); 218 + 219 + $default_ports = array( 220 + 'ssh' => 22, 221 + 'http' => 80, 222 + 'https' => 443, 223 + ); 224 + 225 + $uri = new PhutilURI($raw_uri); 226 + if (!$uri->getProtocol()) { 227 + $git_uri = new PhutilGitURI($raw_uri); 228 + 229 + // We must normalize this Git-style URI into a normal URI 230 + $must_normalize = ($port && ($port != $default_ports['ssh'])); 231 + if ($must_normalize || $normalize) { 232 + $domain = $git_uri->getDomain(); 233 + 234 + 235 + $uri = id(new PhutilURI("ssh://{$domain}")) 236 + ->setUser($git_uri->getUser()) 237 + ->setPath($git_uri->getPath()); 238 + } else { 239 + $uri = $git_uri; 240 + } 241 + } 242 + 243 + $is_normal = ($uri instanceof PhutilURI); 244 + 245 + if ($is_normal) { 246 + $protocol = $this->getForcedProtocol(); 247 + if ($protocol) { 248 + $uri->setProtocol($protocol); 249 + } 250 + 251 + if ($port) { 252 + $uri->setPort($port); 253 + } 254 + 255 + // Remove any explicitly set default ports. 256 + $uri_port = $uri->getPort(); 257 + $uri_protocol = $uri->getProtocol(); 258 + 259 + $uri_default = idx($default_ports, $uri_protocol); 260 + if ($uri_default && ($uri_default == $uri_port)) { 261 + $uri->setPort(null); 262 + } 201 263 } 202 264 203 265 $user = $this->getForcedUser(); ··· 210 272 $uri->setDomain($host); 211 273 } 212 274 213 - $port = $this->getForcedPort(); 214 - if ($port) { 215 - $uri->setPort($port); 216 - } 217 - 218 275 $path = $this->getForcedPath(); 219 276 if ($path) { 220 277 $uri->setPath($path); ··· 222 279 223 280 return $uri; 224 281 } 282 + 225 283 226 284 private function getForcedProtocol() { 227 285 switch ($this->getBuiltinProtocol()) { ··· 446 504 ); 447 505 } 448 506 507 + public function newCommandEngine() { 508 + $repository = $this->getRepository(); 509 + $protocol = $this->getEffectiveURI()->getProtocol(); 510 + 511 + return DiffusionCommandEngine::newCommandEngine($repository) 512 + ->setCredentialPHID($this->getCredentialPHID()) 513 + ->setProtocol($protocol); 514 + } 515 + 516 + 449 517 450 518 /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 451 519 ··· 569 637 'repositoryPHID' => $this->getRepositoryPHID(), 570 638 'uri' => array( 571 639 'raw' => $this->getURI(), 572 - 'effective' => (string)$this->getDisplayURI(), 640 + 'display' => (string)$this->getDisplayURI(), 641 + 'effective' => (string)$this->getEffectiveURI(), 573 642 ), 574 643 'io' => array( 575 644 'raw' => $this->getIOType(),
+38
src/applications/repository/storage/PhabricatorRepositoryURITransaction.php
··· 18 18 return PhabricatorRepositoryURIPHIDType::TYPECONST; 19 19 } 20 20 21 + public function getRequiredHandlePHIDs() { 22 + $phids = parent::getRequiredHandlePHIDs(); 23 + 24 + $old = $this->getOldValue(); 25 + $new = $this->getNewValue(); 26 + 27 + switch ($this->getTransactionType()) { 28 + case self::TYPE_CREDENTIAL: 29 + if ($old) { 30 + $phids[] = $old; 31 + } 32 + if ($new) { 33 + $phids[] = $new; 34 + } 35 + break; 36 + } 37 + 38 + return $phids; 39 + } 40 + 21 41 public function getTitle() { 22 42 $author_phid = $this->getAuthorPHID(); 23 43 ··· 60 80 return pht( 61 81 '%s enabled this URI.', 62 82 $this->renderHandleLink($author_phid)); 83 + } 84 + case self::TYPE_CREDENTIAL: 85 + if ($old && $new) { 86 + return pht( 87 + '%s changed the credential for this URI from %s to %s.', 88 + $this->renderHandleLink($author_phid), 89 + $this->renderHandleLink($old), 90 + $this->renderHandleLink($new)); 91 + } else if ($old) { 92 + return pht( 93 + '%s removed %s as the credential for this URI.', 94 + $this->renderHandleLink($author_phid), 95 + $this->renderHandleLink($old)); 96 + } else if ($new) { 97 + return pht( 98 + '%s set the credential for this URI to %s.', 99 + $this->renderHandleLink($author_phid), 100 + $this->renderHandleLink($new)); 63 101 } 64 102 65 103 }
+1
src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php
··· 34 34 ->execute(); 35 35 36 36 return id(new PassphraseCredentialControl()) 37 + ->setViewer($this->getViewer()) 37 38 ->setLabel($this->getFieldName()) 38 39 ->setName($this->getFieldKey()) 39 40 ->setCaption($this->getCaption())