Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15492852
D8607.id20397.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D8607.id20397.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
@@ -2088,6 +2088,7 @@
'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php',
'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php',
'PhabricatorStandardCustomFieldBool' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php',
+ 'PhabricatorStandardCustomFieldCredential' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php',
'PhabricatorStandardCustomFieldDate' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDate.php',
'PhabricatorStandardCustomFieldHeader' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php',
'PhabricatorStandardCustomFieldInt' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php',
@@ -4931,6 +4932,7 @@
'PhabricatorSourceCodeView' => 'AphrontView',
'PhabricatorStandardCustomField' => 'PhabricatorCustomField',
'PhabricatorStandardCustomFieldBool' => 'PhabricatorStandardCustomField',
+ 'PhabricatorStandardCustomFieldCredential' => 'PhabricatorStandardCustomField',
'PhabricatorStandardCustomFieldDate' => 'PhabricatorStandardCustomField',
'PhabricatorStandardCustomFieldHeader' => 'PhabricatorStandardCustomField',
'PhabricatorStandardCustomFieldInt' => 'PhabricatorStandardCustomField',
diff --git a/src/applications/passphrase/credentialtype/PassphraseCredentialType.php b/src/applications/passphrase/credentialtype/PassphraseCredentialType.php
--- a/src/applications/passphrase/credentialtype/PassphraseCredentialType.php
+++ b/src/applications/passphrase/credentialtype/PassphraseCredentialType.php
@@ -33,6 +33,14 @@
return $types;
}
+ public static function getAllProvidesTypes() {
+ $types = array();
+ foreach (self::getAllTypes() as $type) {
+ $types[] = $type->getProvidesType();
+ }
+ return array_unique($types);
+ }
+
public static function getTypeByConstant($constant) {
$all = self::getAllTypes();
$all = mpull($all, null, 'getCredentialType');
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
@@ -98,4 +98,63 @@
));
}
+ /**
+ * 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;
+ }
+
+
}
diff --git a/src/applications/repository/editor/PhabricatorRepositoryEditor.php b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
--- a/src/applications/repository/editor/PhabricatorRepositoryEditor.php
+++ b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
@@ -310,4 +310,33 @@
}
}
+ protected function validateTransaction(
+ PhabricatorLiskDAO $object,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateTransaction($object, $type, $xactions);
+
+ switch ($type) {
+ case self::TYPE_CREDENTIAL:
+ $ok = PassphraseCredentialControl::validateTransactions(
+ $this->getActor(),
+ $xactions);
+ if (!$ok) {
+ foreach ($xactions as $xaction) {
+ $errors[] = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht(
+ 'The selected credential does not exist, or you do not have '.
+ 'permission to use it.'),
+ $xaction);
+ }
+ }
+ break;
+ }
+
+ return $errors;
+ }
+
}
diff --git a/src/docs/user/configuration/custom_fields.diviner b/src/docs/user/configuration/custom_fields.diviner
--- a/src/docs/user/configuration/custom_fields.diviner
+++ b/src/docs/user/configuration/custom_fields.diviner
@@ -121,6 +121,14 @@
into the new task, while others are not; by default, fields are not copied.
If you want this field to be copied, specify `true` for the `copy` property.
+Internally, Phabricator implements some additional custom field types and
+options. These are not intended for general use and are subject to abrupt
+change, but are documented here for completeness:
+
+ - **Credentials**: Controls with type `credential` allow selection of a
+ Passphrase credential which provides `credential.provides`, and creation
+ of credentials of `credential.type`.
+
= Advanced Custom Fields =
If you want custom fields to have advanced behaviors (sophisticated rendering,
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php
@@ -0,0 +1,138 @@
+<?php
+
+final class PhabricatorStandardCustomFieldCredential
+ extends PhabricatorStandardCustomField {
+
+ public function getFieldType() {
+ return 'credential';
+ }
+
+ public function buildFieldIndexes() {
+ $indexes = array();
+
+ $value = $this->getFieldValue();
+ if (strlen($value)) {
+ $indexes[] = $this->newStringIndex($value);
+ }
+
+ return $indexes;
+ }
+
+ public function renderEditControl(array $handles) {
+ $provides_type = $this->getFieldConfigValue('credential.provides');
+ $credential_type = $this->getFieldConfigValue('credential.type');
+
+ $all_types = PassphraseCredentialType::getAllProvidesTypes();
+ if (!in_array($provides_type, $all_types)) {
+ $provides_type = PassphraseCredentialTypePassword::PROVIDES_TYPE;
+ }
+
+ $credentials = id(new PassphraseCredentialQuery())
+ ->setViewer($this->getViewer())
+ ->withIsDestroyed(false)
+ ->withProvidesTypes(array($provides_type))
+ ->execute();
+
+ return id(new PassphraseCredentialControl())
+ ->setLabel($this->getFieldName())
+ ->setName($this->getFieldKey())
+ ->setCaption($this->getCaption())
+ ->setAllowNull(!$this->getRequired())
+ ->setCredentialType($credential_type)
+ ->setValue($this->getFieldValue())
+ ->setError($this->getFieldError())
+ ->setOptions($credentials);
+ }
+
+ public function getRequiredHandlePHIDsForPropertyView() {
+ $value = $this->getFieldValue();
+ if ($value) {
+ return array($value);
+ }
+ return array();
+ }
+
+ public function renderPropertyViewValue(array $handles) {
+ $value = $this->getFieldValue();
+ if ($value) {
+ return $handles[$value]->renderLink();
+ }
+ return null;
+ }
+
+ public function validateApplicationTransactions(
+ PhabricatorApplicationTransactionEditor $editor,
+ $type,
+ array $xactions) {
+
+ $errors = parent::validateApplicationTransactions(
+ $editor,
+ $type,
+ $xactions);
+
+ $ok = PassphraseCredentialControl::validateTransactions(
+ $this->getViewer(),
+ $xactions);
+
+ if (!$ok) {
+ foreach ($xactions as $xaction) {
+ $errors[] = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht(
+ 'The selected credential does not exist, or you do not have '.
+ 'permission to use it.'),
+ $xaction);
+ $this->setFieldError(pht('Invalid'));
+ }
+ }
+
+ return $errors;
+ }
+
+ public function getApplicationTransactionRequiredHandlePHIDs(
+ PhabricatorApplicationTransaction $xaction) {
+ $phids = array();
+ $old = $xaction->getOldValue();
+ $new = $xaction->getNewValue();
+ if ($old) {
+ $phids[] = $old;
+ }
+ if ($new) {
+ $phids[] = $new;
+ }
+ return $phids;
+ }
+
+
+ public function getApplicationTransactionTitle(
+ PhabricatorApplicationTransaction $xaction) {
+ $author_phid = $xaction->getAuthorPHID();
+
+ $old = $xaction->getOldValue();
+ $new = $xaction->getNewValue();
+
+ if ($old && !$new) {
+ return pht(
+ '%s removed %s as %s.',
+ $xaction->renderHandleLink($author_phid),
+ $xaction->renderHandleLink($old),
+ $this->getFieldName());
+ } else if ($new && !$old) {
+ return pht(
+ '%s set %s to %s.',
+ $xaction->renderHandleLink($author_phid),
+ $this->getFieldName(),
+ $xaction->renderHandleLink($new));
+ } else {
+ return pht(
+ '%s changed %s from %s to %s.',
+ $xaction->renderHandleLink($author_phid),
+ $this->getFieldName(),
+ $xaction->renderHandleLink($old),
+ $xaction->renderHandleLink($new));
+ }
+ }
+
+
+}
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php
@@ -68,7 +68,7 @@
return array();
}
- public function getRequiredHandlePHIDsForProperyView() {
+ public function getRequiredHandlePHIDsForPropertyView() {
$value = $this->getFieldValue();
if ($value) {
return $value;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 13, 6:56 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7715618
Default Alt Text
D8607.id20397.diff (10 KB)
Attached To
Mode
D8607: Implement a "credential" standard custom field
Attached
Detach File
Event Timeline
Log In to Comment