mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-07 21:31:02 +01:00
99718b61d8
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
200 lines
5.3 KiB
PHP
200 lines
5.3 KiB
PHP
<?php
|
|
|
|
final class PassphraseCredentialControl extends AphrontFormControl {
|
|
|
|
private $options = array();
|
|
private $credentialType;
|
|
private $defaultUsername;
|
|
private $allowNull;
|
|
|
|
public function setAllowNull($allow_null) {
|
|
$this->allowNull = $allow_null;
|
|
return $this;
|
|
}
|
|
|
|
public function setDefaultUsername($default_username) {
|
|
$this->defaultUsername = $default_username;
|
|
return $this;
|
|
}
|
|
|
|
public function setCredentialType($credential_type) {
|
|
$this->credentialType = $credential_type;
|
|
return $this;
|
|
}
|
|
|
|
public function getCredentialType() {
|
|
return $this->credentialType;
|
|
}
|
|
|
|
public function setOptions(array $options) {
|
|
assert_instances_of($options, 'PassphraseCredential');
|
|
$this->options = $options;
|
|
return $this;
|
|
}
|
|
|
|
protected function getCustomControlClass() {
|
|
return 'passphrase-credential-control';
|
|
}
|
|
|
|
protected function renderInput() {
|
|
|
|
$options_map = array();
|
|
foreach ($this->options as $option) {
|
|
$options_map[$option->getPHID()] = pht(
|
|
'%s %s',
|
|
$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;
|
|
} else {
|
|
if (!$options_map) {
|
|
$options_map[''] = pht('(No Existing Credentials)');
|
|
$disabled = true;
|
|
}
|
|
}
|
|
|
|
Javelin::initBehavior('passphrase-credential-control');
|
|
|
|
$options = AphrontFormSelectControl::renderSelectTag(
|
|
$this->getValue(),
|
|
$options_map,
|
|
array(
|
|
'id' => $this->getControlID(),
|
|
'name' => $this->getName(),
|
|
'disabled' => $disabled ? 'disabled' : null,
|
|
'sigil' => 'passphrase-credential-select',
|
|
));
|
|
|
|
if ($this->credentialType) {
|
|
$button = javelin_tag(
|
|
'a',
|
|
array(
|
|
'href' => '#',
|
|
'class' => 'button grey',
|
|
'sigil' => 'passphrase-credential-add',
|
|
'mustcapture' => true,
|
|
),
|
|
pht('Add Credential'));
|
|
} else {
|
|
$button = null;
|
|
}
|
|
|
|
return javelin_tag(
|
|
'div',
|
|
array(
|
|
'sigil' => 'passphrase-credential-control',
|
|
'meta' => array(
|
|
'type' => $this->getCredentialType(),
|
|
'username' => $this->defaultUsername,
|
|
'allowNull' => $this->allowNull,
|
|
),
|
|
),
|
|
array(
|
|
$options,
|
|
$button,
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Verify that a given actor has permission to use all of the credentials
|
|
* in a list of credential transactions.
|
|
*
|
|
* In general, the rule here is:
|
|
*
|
|
* - If you're editing an object and it uses a credential you can't use,
|
|
* that's fine as long as you don't change the credential.
|
|
* - If you do change the credential, the new credential must be one you
|
|
* can use.
|
|
*
|
|
* @param PhabricatorUser The acting user.
|
|
* @param list<PhabricatorApplicationTransaction> List of credential altering
|
|
* transactions.
|
|
* @return bool True if the transactions are valid.
|
|
*/
|
|
public static function validateTransactions(
|
|
PhabricatorUser $actor,
|
|
array $xactions) {
|
|
|
|
$new_phids = array();
|
|
foreach ($xactions as $xaction) {
|
|
$new = $xaction->getNewValue();
|
|
if (!$new) {
|
|
// Removing a credential, so this is OK.
|
|
continue;
|
|
}
|
|
|
|
$old = $xaction->getOldValue();
|
|
if ($old == $new) {
|
|
// This is a no-op transaction, so this is also OK.
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, we need to check this credential.
|
|
$new_phids[] = $new;
|
|
}
|
|
|
|
if (!$new_phids) {
|
|
// No new credentials being set, so this is fine.
|
|
return true;
|
|
}
|
|
|
|
$usable_credentials = id(new PassphraseCredentialQuery())
|
|
->setViewer($actor)
|
|
->withPHIDs($new_phids)
|
|
->execute();
|
|
$usable_credentials = mpull($usable_credentials, null, 'getPHID');
|
|
|
|
foreach ($new_phids as $phid) {
|
|
if (empty($usable_credentials[$phid])) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|