Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13964372
D15829.id38132.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Referenced Files
None
Subscribers
None
D15829.id38132.diff
View Options
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
@@ -789,6 +789,7 @@
'DiffusionRepositorySymbolsManagementPanel' => 'applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php',
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
'DiffusionRepositoryTestAutomationController' => 'applications/diffusion/controller/DiffusionRepositoryTestAutomationController.php',
+ 'DiffusionRepositoryURICredentialController' => 'applications/diffusion/controller/DiffusionRepositoryURICredentialController.php',
'DiffusionRepositoryURIDisableController' => 'applications/diffusion/controller/DiffusionRepositoryURIDisableController.php',
'DiffusionRepositoryURIEditController' => 'applications/diffusion/controller/DiffusionRepositoryURIEditController.php',
'DiffusionRepositoryURIViewController' => 'applications/diffusion/controller/DiffusionRepositoryURIViewController.php',
@@ -5020,6 +5021,7 @@
'DiffusionRepositorySymbolsManagementPanel' => 'DiffusionRepositoryManagementPanel',
'DiffusionRepositoryTag' => 'Phobject',
'DiffusionRepositoryTestAutomationController' => 'DiffusionRepositoryEditController',
+ 'DiffusionRepositoryURICredentialController' => 'DiffusionController',
'DiffusionRepositoryURIDisableController' => 'DiffusionController',
'DiffusionRepositoryURIEditController' => 'DiffusionController',
'DiffusionRepositoryURIViewController' => 'DiffusionController',
diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
--- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
+++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
@@ -97,6 +97,8 @@
=> 'DiffusionRepositoryURIDisableController',
$this->getEditRoutePattern('edit/')
=> 'DiffusionRepositoryURIEditController',
+ 'credential/(?P<id>[0-9]\d*)/(?P<action>edit|remove)/'
+ => 'DiffusionRepositoryURICredentialController',
),
'edit/' => array(
'' => 'DiffusionRepositoryEditMainController',
diff --git a/src/applications/diffusion/controller/DiffusionMirrorEditController.php b/src/applications/diffusion/controller/DiffusionMirrorEditController.php
--- a/src/applications/diffusion/controller/DiffusionMirrorEditController.php
+++ b/src/applications/diffusion/controller/DiffusionMirrorEditController.php
@@ -108,7 +108,7 @@
->setName('remoteURI')
->setValue($v_remote)
->setError($e_remote))
- ->appendChild(
+ ->appendControl(
id(new PassphraseCredentialControl())
->setLabel(pht('Credentials'))
->setName('credential')
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php
@@ -510,6 +510,7 @@
->setAdjustFormPageCallback(array($this, 'adjustAuthPage'))
->addControl(
id(new PassphraseCredentialControl())
+ ->setViewer($this->getViewer())
->setName('credential'));
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php b/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/controller/DiffusionRepositoryURICredentialController.php
@@ -0,0 +1,159 @@
+<?php
+
+final class DiffusionRepositoryURICredentialController
+ extends DiffusionController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $response = $this->loadDiffusionContextForEdit();
+ if ($response) {
+ return $response;
+ }
+
+ $viewer = $this->getViewer();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ $id = $request->getURIData('id');
+ $uri = id(new PhabricatorRepositoryURIQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->withRepositories(array($repository))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$uri) {
+ return new Aphront404Response();
+ }
+
+ $is_builtin = $uri->isBuiltin();
+ $has_credential = (bool)$uri->getCredentialPHID();
+ $view_uri = $uri->getViewURI();
+ $is_remove = ($request->getURIData('action') == 'remove');
+
+ if ($is_builtin) {
+ return $this->newDialog()
+ ->setTitle(pht('Builtin URIs Do Not Use Credentials'))
+ ->appendParagraph(
+ pht(
+ 'You can not set a credential for builtin URIs which Phabricator '.
+ 'hosts and serves. Phabricator does not fetch from these URIs or '.
+ 'push to these URIs, and does not need credentials to '.
+ 'authenticate any activity against them.'))
+ ->addCancelButton($view_uri);
+ }
+
+ if ($request->isFormPost()) {
+ $xactions = array();
+
+ if ($is_remove) {
+ $new_phid = null;
+ } else {
+ $new_phid = $request->getStr('credentialPHID');
+ }
+
+ $type_credential = PhabricatorRepositoryURITransaction::TYPE_CREDENTIAL;
+
+ $xactions[] = id(new PhabricatorRepositoryURITransaction())
+ ->setTransactionType($type_credential)
+ ->setNewValue($new_phid);
+
+ $editor = id(new DiffusionURIEditor())
+ ->setActor($viewer)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true)
+ ->setContentSourceFromRequest($request)
+ ->applyTransactions($uri, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($view_uri);
+ }
+
+ $command_engine = $uri->newCommandEngine();
+ $is_supported = $command_engine->isCredentialSupported();
+
+ $body = null;
+ $form = null;
+ $width = AphrontDialogView::WIDTH_DEFAULT;
+ if ($is_remove) {
+ if ($has_credential) {
+ $title = pht('Remove Credential');
+ $body = pht(
+ 'This credential will no longer be used to authenticate activity '.
+ 'against this URI.');
+ $button = pht('Remove Credential');
+ } else {
+ $title = pht('No Credential');
+ $body = pht(
+ 'This URI does not have an associated credential.');
+ $button = null;
+ }
+ } else if (!$is_supported) {
+ $title = pht('Unauthenticated Protocol');
+ $body = pht(
+ 'The protocol for this URI ("%s") does not use authentication, so '.
+ 'you can not provide a credential.',
+ $command_engine->getDisplayProtocol());
+ $button = null;
+ } else {
+ $effective_uri = $uri->getEffectiveURI();
+
+ $label = $command_engine->getPassphraseCredentialLabel();
+ $credential_type = $command_engine->getPassphraseDefaultCredentialType();
+
+ $provides_type = $command_engine->getPassphraseProvidesCredentialType();
+ $options = id(new PassphraseCredentialQuery())
+ ->setViewer($viewer)
+ ->withIsDestroyed(false)
+ ->withProvidesTypes(array($provides_type))
+ ->execute();
+
+ $control = id(new PassphraseCredentialControl())
+ ->setName('credentialPHID')
+ ->setLabel($label)
+ ->setValue($uri->getCredentialPHID())
+ ->setCredentialType($credential_type)
+ ->setOptions($options);
+
+ $default_user = $effective_uri->getUser();
+ if (strlen($default_user)) {
+ $control->setDefaultUsername($default_user);
+ }
+
+ $form = id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->appendControl($control);
+
+ if ($has_credential) {
+ $title = pht('Update Credential');
+ $button = pht('Update Credential');
+ } else {
+ $title = pht('Set Credential');
+ $button = pht('Set Credential');
+ }
+
+ $width = AphrontDialogView::WIDTH_FORM;
+ }
+
+ $dialog = $this->newDialog()
+ ->setWidth($width)
+ ->setTitle($title)
+ ->addCancelButton($view_uri);
+
+ if ($body) {
+ $dialog->appendParagraph($body);
+ }
+
+ if ($form) {
+ $dialog->appendForm($form);
+ }
+
+ if ($button) {
+ $dialog->addSubmitButton($button);
+ }
+
+ return $dialog;
+ }
+
+}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php b/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryURIViewController.php
@@ -82,6 +82,7 @@
private function buildCurtain(PhabricatorRepositoryURI $uri) {
$viewer = $this->getViewer();
+ $repository = $uri->getRepository();
$id = $uri->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
@@ -89,7 +90,6 @@
$uri,
PhabricatorPolicyCapability::CAN_EDIT);
-
$curtain = $this->newCurtainView($uri);
$edit_uri = $uri->getEditURI();
@@ -102,6 +102,43 @@
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
+ $credential_uri = $repository->getPathURI("uri/credential/{$id}/edit/");
+ $remove_uri = $repository->getPathURI("uri/credential/{$id}/remove/");
+ $has_credential = (bool)$uri->getCredentialPHID();
+
+ if ($uri->isBuiltin()) {
+ $can_credential = false;
+ } else if (!$uri->newCommandEngine()->isCredentialSupported()) {
+ $can_credential = false;
+ } else {
+ $can_credential = true;
+ }
+
+ $can_update = ($can_edit && $can_credential);
+ $can_remove = ($can_edit && $has_credential);
+
+ if ($has_credential) {
+ $credential_name = pht('Update Credential');
+ } else {
+ $credential_name = pht('Set Credential');
+ }
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setIcon('fa-key')
+ ->setName($credential_name)
+ ->setHref($credential_uri)
+ ->setWorkflow(true)
+ ->setDisabled(!$can_edit));
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setIcon('fa-times')
+ ->setName(pht('Remove Credential'))
+ ->setHref($remove_uri)
+ ->setWorkflow(true)
+ ->setDisabled(!$can_remove));
+
if ($uri->getIsDisabled()) {
$disable_name = pht('Enable URI');
$disable_icon = 'fa-check';
@@ -110,7 +147,7 @@
$disable_icon = 'fa-ban';
}
- $disable_uri = $uri->getRepository()->getPathURI("uri/disable/{$id}/");
+ $disable_uri = $repository->getPathURI("uri/disable/{$id}/");
$curtain->addAction(
id(new PhabricatorActionView())
@@ -130,7 +167,84 @@
->setUser($viewer);
$properties->addProperty(pht('URI'), $uri->getDisplayURI());
- $properties->addProperty(pht('Credential'), 'TODO');
+
+ $credential_phid = $uri->getCredentialPHID();
+ $command_engine = $uri->newCommandEngine();
+ $is_optional = $command_engine->isCredentialOptional();
+ $is_supported = $command_engine->isCredentialSupported();
+ $is_builtin = $uri->isBuiltin();
+
+ if ($is_builtin) {
+ $credential_icon = 'fa-circle-o';
+ $credential_color = 'grey';
+ $credential_label = pht('Builtin');
+ $credential_note = pht('Builtin URIs do not use credentials.');
+ } else if (!$is_supported) {
+ $credential_icon = 'fa-circle-o';
+ $credential_color = 'grey';
+ $credential_label = pht('Not Supported');
+ $credential_note = pht('This protocol does not support authentication.');
+ } else if (!$credential_phid) {
+ if ($is_optional) {
+ $credential_icon = 'fa-circle-o';
+ $credential_color = 'green';
+ $credential_label = pht('No Credential');
+ $credential_note = pht('Configured for anonymous access.');
+ } else {
+ $credential_icon = 'fa-times';
+ $credential_color = 'red';
+ $credential_label = pht('Required');
+ $credential_note = pht('Credential required but not configured.');
+ }
+ } else {
+ // Don't raise a policy exception if we can't see the credential.
+ $credentials = id(new PassphraseCredentialQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($credential_phid))
+ ->execute();
+ $credential = head($credentials);
+
+ if (!$credential) {
+ $handles = $viewer->loadHandles(array($credential_phid));
+ $handle = $handles[$credential_phid];
+ if ($handle->getPolicyFiltered()) {
+ $credential_icon = 'fa-lock';
+ $credential_color = 'grey';
+ $credential_label = pht('Restricted');
+ $credential_note = pht(
+ 'You do not have permission to view the configured '.
+ 'credential.');
+ } else {
+ $credential_icon = 'fa-times';
+ $credential_color = 'red';
+ $credential_label = pht('Invalid');
+ $credential_note = pht('Configured credential is invalid.');
+ }
+ } else {
+ $provides = $credential->getProvidesType();
+ $needs = $command_engine->getPassphraseProvidesCredentialType();
+ if ($provides != $needs) {
+ $credential_icon = 'fa-times';
+ $credential_color = 'red';
+ $credential_label = pht('Wrong Type');
+ } else {
+ $credential_icon = 'fa-check';
+ $credential_color = 'green';
+ $credential_label = $command_engine->getPassphraseCredentialLabel();
+ }
+ $credential_note = $viewer->renderHandle($credential_phid);
+ }
+ }
+
+ $credential_item = id(new PHUIStatusItemView())
+ ->setIcon($credential_icon, $credential_color)
+ ->setTarget(phutil_tag('strong', array(), $credential_label))
+ ->setNote($credential_note);
+
+ $credential_view = id(new PHUIStatusListView())
+ ->addItem($credential_item);
+
+ $properties->addProperty(pht('Credential'), $credential_view);
$io_type = $uri->getEffectiveIOType();
diff --git a/src/applications/diffusion/editor/DiffusionURIEditEngine.php b/src/applications/diffusion/editor/DiffusionURIEditEngine.php
--- a/src/applications/diffusion/editor/DiffusionURIEditEngine.php
+++ b/src/applications/diffusion/editor/DiffusionURIEditEngine.php
@@ -83,6 +83,14 @@
protected function buildCustomEditFields($object) {
$viewer = $this->getViewer();
+ if ($object->isBuiltin()) {
+ $is_builtin = true;
+ $uri_value = (string)$object->getDisplayURI();
+ } else {
+ $is_builtin = false;
+ $uri_value = $object->getURI();
+ }
+
return array(
id(new PhabricatorHandlesEditField())
->setKey('repository')
@@ -104,12 +112,13 @@
id(new PhabricatorTextEditField())
->setKey('uri')
->setLabel(pht('URI'))
- ->setIsRequired(true)
->setTransactionType(PhabricatorRepositoryURITransaction::TYPE_URI)
->setDescription(pht('The repository URI.'))
->setConduitDescription(pht('Change the repository URI.'))
->setConduitTypeDescription(pht('New repository URI.'))
- ->setValue($object->getURI()),
+ ->setIsRequired(!$is_builtin)
+ ->setIsLocked($is_builtin)
+ ->setValue($uri_value),
id(new PhabricatorSelectEditField())
->setKey('io')
->setLabel(pht('I/O Type'))
diff --git a/src/applications/diffusion/editor/DiffusionURIEditor.php b/src/applications/diffusion/editor/DiffusionURIEditor.php
--- a/src/applications/diffusion/editor/DiffusionURIEditor.php
+++ b/src/applications/diffusion/editor/DiffusionURIEditor.php
@@ -70,7 +70,42 @@
switch ($xaction->getTransactionType()) {
case PhabricatorRepositoryURITransaction::TYPE_URI:
+ if (!$this->getIsNewObject()) {
+ $old_uri = $object->getEffectiveURI();
+ } else {
+ $old_uri = null;
+ }
+
$object->setURI($xaction->getNewValue());
+
+ // If we've changed the domain or protocol of the URI, remove the
+ // current credential. This improves behavior in several cases:
+
+ // If a user switches between protocols with different credential
+ // types, like HTTP and SSH, the old credential won't be valid anyway.
+ // It's cleaner to remove it than leave a bad credential in place.
+
+ // If a user switches hosts, the old credential is probably not
+ // correct (and potentially confusing/misleading). Removing it forces
+ // users to double check that they have the correct credentials.
+
+ // If an attacker can't see a symmetric credential like a username and
+ // password, they could still potentially capture it by changing the
+ // host for a URI that uses it to `evil.com`, a server they control,
+ // then observing the requests. Removing the credential prevents this
+ // kind of escalation.
+
+ // Since port and path changes are less likely to fall among these
+ // cases, they don't trigger a credential wipe.
+
+ $new_uri = $object->getEffectiveURI();
+ if ($old_uri) {
+ $new_proto = ($old_uri->getProtocol() != $new_uri->getProtocol());
+ $new_domain = ($old_uri->getDomain() != $new_uri->getDomain());
+ if ($new_proto || $new_domain) {
+ $object->setCredentialPHID(null);
+ }
+ }
break;
case PhabricatorRepositoryURITransaction::TYPE_IO:
$object->setIOType($xaction->getNewValue());
@@ -184,6 +219,11 @@
continue;
}
+ // Anyone who can edit a URI can remove the credential.
+ if ($credential_phid === null) {
+ continue;
+ }
+
$credential = id(new PassphraseCredentialQuery())
->setViewer($viewer)
->withPHIDs(array($credential_phid))
diff --git a/src/applications/diffusion/protocol/DiffusionCommandEngine.php b/src/applications/diffusion/protocol/DiffusionCommandEngine.php
--- a/src/applications/diffusion/protocol/DiffusionCommandEngine.php
+++ b/src/applications/diffusion/protocol/DiffusionCommandEngine.php
@@ -57,6 +57,10 @@
return $this->protocol;
}
+ public function getDisplayProtocol() {
+ return $this->getProtocol().'://';
+ }
+
public function setCredentialPHID($credential_phid) {
$this->credentialPHID = $credential_phid;
return $this;
@@ -197,34 +201,82 @@
return $env;
}
- protected function isSSHProtocol() {
+ public function isSSHProtocol() {
return ($this->getProtocol() == 'ssh');
}
- protected function isSVNProtocol() {
+ public function isSVNProtocol() {
return ($this->getProtocol() == 'svn');
}
- protected function isSVNSSHProtocol() {
+ public function isSVNSSHProtocol() {
return ($this->getProtocol() == 'svn+ssh');
}
- protected function isHTTPProtocol() {
+ public function isHTTPProtocol() {
return ($this->getProtocol() == 'http');
}
- protected function isHTTPSProtocol() {
+ public function isHTTPSProtocol() {
return ($this->getProtocol() == 'https');
}
- protected function isAnyHTTPProtocol() {
+ public function isAnyHTTPProtocol() {
return ($this->isHTTPProtocol() || $this->isHTTPSProtocol());
}
- protected function isAnySSHProtocol() {
+ public function isAnySSHProtocol() {
return ($this->isSSHProtocol() || $this->isSVNSSHProtocol());
}
+ public function isCredentialSupported() {
+ return ($this->getPassphraseProvidesCredentialType() !== null);
+ }
+
+ public function isCredentialOptional() {
+ if ($this->isAnySSHProtocol()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function getPassphraseCredentialLabel() {
+ if ($this->isAnySSHProtocol()) {
+ return pht('SSH Key');
+ }
+
+ if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
+ return pht('Password');
+ }
+
+ return null;
+ }
+
+ public function getPassphraseDefaultCredentialType() {
+ if ($this->isAnySSHProtocol()) {
+ return PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE;
+ }
+
+ if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
+ return PassphrasePasswordCredentialType::CREDENTIAL_TYPE;
+ }
+
+ return null;
+ }
+
+ public function getPassphraseProvidesCredentialType() {
+ if ($this->isAnySSHProtocol()) {
+ return PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
+ }
+
+ if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
+ return PassphrasePasswordCredentialType::PROVIDES_TYPE;
+ }
+
+ return null;
+ }
+
protected function getSSHWrapper() {
$root = dirname(phutil_get_library_root('phabricator'));
return $root.'/bin/ssh-connect';
diff --git a/src/applications/passphrase/view/PassphraseCredentialControl.php b/src/applications/passphrase/view/PassphraseCredentialControl.php
--- a/src/applications/passphrase/view/PassphraseCredentialControl.php
+++ b/src/applications/passphrase/view/PassphraseCredentialControl.php
@@ -42,10 +42,50 @@
foreach ($this->options as $option) {
$options_map[$option->getPHID()] = pht(
'%s %s',
- 'K'.$option->getID(),
+ $option->getMonogram(),
$option->getName());
}
+ // The user editing the form may not have permission to see the current
+ // credential. Populate it into the menu to allow them to save the form
+ // without making any changes.
+ $current_phid = $this->getValue();
+ if (strlen($current_phid) && empty($options_map[$current_phid])) {
+ $viewer = $this->getViewer();
+
+ $user_credential = id(new PassphraseCredentialQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($current_phid))
+ ->executeOne();
+ if (!$user_credential) {
+ // Pull the credential with the ominipotent viewer so we can look up
+ // the ID and tell if it's restricted or invalid.
+ $omnipotent_credential = id(new PassphraseCredentialQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs(array($current_phid))
+ ->executeOne();
+ if ($omnipotent_credential) {
+ $current_name = pht(
+ '%s (Restricted Credential)',
+ $omnipotent_credential->getMonogram());
+ } else {
+ $current_name = pht(
+ 'Invalid Credential ("%s")',
+ $current_phid);
+ }
+ } else {
+ $current_name = pht(
+ '%s %s',
+ $user_credential->getMonogram(),
+ $user_credential->getName());
+ }
+
+ $options_map = array(
+ $current_phid => $current_name,
+ ) + $options_map;
+ }
+
+
$disabled = $this->getDisabled();
if ($this->allowNull) {
$options_map = array('' => pht('(No Credentials)')) + $options_map;
diff --git a/src/applications/repository/storage/PhabricatorRepositoryURI.php b/src/applications/repository/storage/PhabricatorRepositoryURI.php
--- a/src/applications/repository/storage/PhabricatorRepositoryURI.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryURI.php
@@ -193,11 +193,73 @@
public function getDisplayURI() {
- $uri = new PhutilURI($this->getURI());
+ return $this->getURIObject(false);
+ }
+
+ public function getEffectiveURI() {
+ return $this->getURIObject(true);
+ }
+
+ private function getURIObject($normalize) {
+ // Users can provide Git/SCP-style URIs in the form "user@host:path".
+ // These are equivalent to "ssh://user@host/path". We use the more standard
+ // form internally, and convert to it if we need to specify a port number,
+ // but try to preserve what the user typed when displaying the URI.
+
+ if ($this->isBuiltin()) {
+ $builtin_protocol = $this->getForcedProtocol();
+ $builtin_domain = $this->getForcedHost();
+ $raw_uri = "{$builtin_protocol}://{$builtin_domain}";
+ } else {
+ $raw_uri = $this->getURI();
+ }
+
+ $port = $this->getForcedPort();
+
+ $default_ports = array(
+ 'ssh' => 22,
+ 'http' => 80,
+ 'https' => 443,
+ );
+
+ $uri = new PhutilURI($raw_uri);
+ if (!$uri->getProtocol()) {
+ $git_uri = new PhutilGitURI($raw_uri);
+
+ // We must normalize this Git-style URI into a normal URI
+ $must_normalize = ($port && ($port != $default_ports['ssh']));
+ if ($must_normalize || $normalize) {
+ $domain = $git_uri->getDomain();
- $protocol = $this->getForcedProtocol();
- if ($protocol) {
- $uri->setProtocol($protocol);
+
+ $uri = id(new PhutilURI("ssh://{$domain}"))
+ ->setUser($git_uri->getUser())
+ ->setPath($git_uri->getPath());
+ } else {
+ $uri = $git_uri;
+ }
+ }
+
+ $is_normal = ($uri instanceof PhutilURI);
+
+ if ($is_normal) {
+ $protocol = $this->getForcedProtocol();
+ if ($protocol) {
+ $uri->setProtocol($protocol);
+ }
+
+ if ($port) {
+ $uri->setPort($port);
+ }
+
+ // Remove any explicitly set default ports.
+ $uri_port = $uri->getPort();
+ $uri_protocol = $uri->getProtocol();
+
+ $uri_default = idx($default_ports, $uri_protocol);
+ if ($uri_default && ($uri_default == $uri_port)) {
+ $uri->setPort(null);
+ }
}
$user = $this->getForcedUser();
@@ -210,11 +272,6 @@
$uri->setDomain($host);
}
- $port = $this->getForcedPort();
- if ($port) {
- $uri->setPort($port);
- }
-
$path = $this->getForcedPath();
if ($path) {
$uri->setPath($path);
@@ -223,6 +280,7 @@
return $uri;
}
+
private function getForcedProtocol() {
switch ($this->getBuiltinProtocol()) {
case self::BUILTIN_PROTOCOL_SSH:
@@ -446,6 +504,16 @@
);
}
+ public function newCommandEngine() {
+ $repository = $this->getRepository();
+ $protocol = $this->getEffectiveURI()->getProtocol();
+
+ return DiffusionCommandEngine::newCommandEngine($repository)
+ ->setCredentialPHID($this->getCredentialPHID())
+ ->setProtocol($protocol);
+ }
+
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
@@ -569,7 +637,8 @@
'repositoryPHID' => $this->getRepositoryPHID(),
'uri' => array(
'raw' => $this->getURI(),
- 'effective' => (string)$this->getDisplayURI(),
+ 'display' => (string)$this->getDisplayURI(),
+ 'effective' => (string)$this->getEffectiveURI(),
),
'io' => array(
'raw' => $this->getIOType(),
diff --git a/src/applications/repository/storage/PhabricatorRepositoryURITransaction.php b/src/applications/repository/storage/PhabricatorRepositoryURITransaction.php
--- a/src/applications/repository/storage/PhabricatorRepositoryURITransaction.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryURITransaction.php
@@ -18,6 +18,26 @@
return PhabricatorRepositoryURIPHIDType::TYPECONST;
}
+ public function getRequiredHandlePHIDs() {
+ $phids = parent::getRequiredHandlePHIDs();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ switch ($this->getTransactionType()) {
+ case self::TYPE_CREDENTIAL:
+ if ($old) {
+ $phids[] = $old;
+ }
+ if ($new) {
+ $phids[] = $new;
+ }
+ break;
+ }
+
+ return $phids;
+ }
+
public function getTitle() {
$author_phid = $this->getAuthorPHID();
@@ -61,6 +81,24 @@
'%s enabled this URI.',
$this->renderHandleLink($author_phid));
}
+ case self::TYPE_CREDENTIAL:
+ if ($old && $new) {
+ return pht(
+ '%s changed the credential for this URI from %s to %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($old),
+ $this->renderHandleLink($new));
+ } else if ($old) {
+ return pht(
+ '%s removed %s as the credential for this URI.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($old));
+ } else if ($new) {
+ return pht(
+ '%s set the credential for this URI to %s.',
+ $this->renderHandleLink($author_phid),
+ $this->renderHandleLink($new));
+ }
}
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php
@@ -34,6 +34,7 @@
->execute();
return id(new PassphraseCredentialControl())
+ ->setViewer($this->getViewer())
->setLabel($this->getFieldName())
->setName($this->getFieldKey())
->setCaption($this->getCaption())
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Oct 16 2024, 8:06 PM (4 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6715231
Default Alt Text
D15829.id38132.diff (28 KB)
Attached To
Mode
D15829: Fill in new URI credential edit web UI interfaces
Attached
Detach File
Event Timeline
Log In to Comment