Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15443583
D8515.id20197.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
D8515.id20197.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
@@ -1024,6 +1024,7 @@
'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php',
'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php',
'PassphraseCredentialListController' => 'applications/passphrase/controller/PassphraseCredentialListController.php',
+ 'PassphraseCredentialPublicController' => 'applications/passphrase/controller/PassphraseCredentialPublicController.php',
'PassphraseCredentialQuery' => 'applications/passphrase/query/PassphraseCredentialQuery.php',
'PassphraseCredentialRevealController' => 'applications/passphrase/controller/PassphraseCredentialRevealController.php',
'PassphraseCredentialSearchEngine' => 'applications/passphrase/query/PassphraseCredentialSearchEngine.php',
@@ -1032,6 +1033,7 @@
'PassphraseCredentialTransactionQuery' => 'applications/passphrase/query/PassphraseCredentialTransactionQuery.php',
'PassphraseCredentialType' => 'applications/passphrase/credentialtype/PassphraseCredentialType.php',
'PassphraseCredentialTypePassword' => 'applications/passphrase/credentialtype/PassphraseCredentialTypePassword.php',
+ 'PassphraseCredentialTypeSSHGeneratedKey' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHGeneratedKey.php',
'PassphraseCredentialTypeSSHPrivateKey' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php',
'PassphraseCredentialTypeSSHPrivateKeyFile' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php',
'PassphraseCredentialTypeSSHPrivateKeyText' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyText.php',
@@ -3676,6 +3678,7 @@
0 => 'PassphraseController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
+ 'PassphraseCredentialPublicController' => 'PassphraseController',
'PassphraseCredentialQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PassphraseCredentialRevealController' => 'PassphraseController',
'PassphraseCredentialSearchEngine' => 'PhabricatorApplicationSearchEngine',
@@ -3684,6 +3687,7 @@
'PassphraseCredentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PassphraseCredentialType' => 'Phobject',
'PassphraseCredentialTypePassword' => 'PassphraseCredentialType',
+ 'PassphraseCredentialTypeSSHGeneratedKey' => 'PassphraseCredentialTypeSSHPrivateKey',
'PassphraseCredentialTypeSSHPrivateKey' => 'PassphraseCredentialType',
'PassphraseCredentialTypeSSHPrivateKeyFile' => 'PassphraseCredentialTypeSSHPrivateKey',
'PassphraseCredentialTypeSSHPrivateKeyText' => 'PassphraseCredentialTypeSSHPrivateKey',
diff --git a/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php b/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php
--- a/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php
+++ b/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php
@@ -40,6 +40,7 @@
'edit/(?:(?P<id>\d+)/)?' => 'PassphraseCredentialEditController',
'destroy/(?P<id>\d+)/' => 'PassphraseCredentialDestroyController',
'reveal/(?P<id>\d+)/' => 'PassphraseCredentialRevealController',
+ 'public/(?P<id>\d+)/' => 'PassphraseCredentialPublicController',
));
}
diff --git a/src/applications/passphrase/controller/PassphraseCredentialEditController.php b/src/applications/passphrase/controller/PassphraseCredentialEditController.php
--- a/src/applications/passphrase/controller/PassphraseCredentialEditController.php
+++ b/src/applications/passphrase/controller/PassphraseCredentialEditController.php
@@ -53,6 +53,10 @@
// Prefill username if provided.
$credential->setUsername($request->getStr('username'));
+
+ if (!$request->getStr('isInitialized')) {
+ $type->didInitializeNewCredential($viewer, $credential);
+ }
}
$errors = array();
@@ -68,6 +72,16 @@
$bullet = "\xE2\x80\xA2";
$v_secret = $credential->getSecretID() ? str_repeat($bullet, 32) : null;
+ if ($is_new && ($v_secret === null)) {
+ // If we're creating a new credential, the credential type may have
+ // populated the secret for us (for example, generated an SSH key). In
+ // this case,
+ try {
+ $v_secret = $credential->getSecret()->openEnvelope();
+ } catch (Exception $ex) {
+ // Ignore this.
+ }
+ }
$validation_exception = null;
$errors = array();
@@ -205,6 +219,7 @@
}
$form
+ ->addHiddenInput('isInitialized', true)
->appendChild(
id(new AphrontFormTextControl())
->setName('name')
diff --git a/src/applications/passphrase/controller/PassphraseCredentialPublicController.php b/src/applications/passphrase/controller/PassphraseCredentialPublicController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/passphrase/controller/PassphraseCredentialPublicController.php
@@ -0,0 +1,59 @@
+<?php
+
+final class PassphraseCredentialPublicController
+ extends PassphraseController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = $data['id'];
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $credential = id(new PassphraseCredentialQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($this->id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ ))
+ ->executeOne();
+ if (!$credential) {
+ return new Aphront404Response();
+ }
+
+ $type = PassphraseCredentialType::getTypeByConstant(
+ $credential->getCredentialType());
+ if (!$type) {
+ throw new Exception(pht('Credential has invalid type "%s"!', $type));
+ }
+
+ if (!$type->hasPublicKey()) {
+ throw new Exception(pht('Credential has no public key!'));
+ }
+
+ $view_uri = '/'.$credential->getMonogram();
+
+ $public_key = $type->getPublicKey($viewer, $credential);
+
+ $body = id(new PHUIFormLayoutView())
+ ->appendChild(
+ id(new AphrontFormTextAreaControl())
+ ->setLabel(pht('Public Key'))
+ ->setReadOnly(true)
+ ->setValue($public_key));
+
+ $dialog = id(new AphrontDialogView())
+ ->setUser($viewer)
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setTitle(pht('Public Key (%s)', $credential->getMonogram()))
+ ->appendChild($body)
+ ->addCancelButton($view_uri, pht('Done'));
+
+ return id(new AphrontDialogResponse())->setDialog($dialog);
+ }
+
+}
diff --git a/src/applications/passphrase/controller/PassphraseCredentialRevealController.php b/src/applications/passphrase/controller/PassphraseCredentialRevealController.php
--- a/src/applications/passphrase/controller/PassphraseCredentialRevealController.php
+++ b/src/applications/passphrase/controller/PassphraseCredentialRevealController.php
@@ -36,15 +36,21 @@
id(new AphrontFormTextAreaControl())
->setLabel(pht('Plaintext'))
->setReadOnly(true)
+ ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
->setValue($credential->getSecret()->openEnvelope()));
} else {
$body = pht('This credential has no associated secret.');
}
+ // NOTE: Disable workflow on the cancel button to reload the page so
+ // the viewer can see that their view was logged.
+
$dialog = id(new AphrontDialogView())
->setUser($viewer)
- ->setTitle(pht('Credential Secret'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->setTitle(pht('Credential Secret (%s)', $credential->getMonogram()))
->appendChild($body)
+ ->setDisableWorkflowOnCancel(true)
->addCancelButton($view_uri, pht('Done'));
$type_secret = PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET;
diff --git a/src/applications/passphrase/controller/PassphraseCredentialViewController.php b/src/applications/passphrase/controller/PassphraseCredentialViewController.php
--- a/src/applications/passphrase/controller/PassphraseCredentialViewController.php
+++ b/src/applications/passphrase/controller/PassphraseCredentialViewController.php
@@ -44,7 +44,7 @@
$crumbs->addTextCrumb('K'.$credential->getID());
$header = $this->buildHeaderView($credential);
- $actions = $this->buildActionView($credential);
+ $actions = $this->buildActionView($credential, $type);
$properties = $this->buildPropertyView($credential, $type, $actions);
$box = id(new PHUIObjectBoxView())
@@ -78,7 +78,9 @@
return $header;
}
- private function buildActionView(PassphraseCredential $credential) {
+ private function buildActionView(
+ PassphraseCredential $credential,
+ PassphraseCredentialType $type) {
$viewer = $this->getRequest()->getUser();
$id = $credential->getID();
@@ -116,6 +118,15 @@
->setHref($this->getApplicationURI("reveal/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
+
+ if ($type->hasPublicKey()) {
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Show Public Key'))
+ ->setIcon('download-alt')
+ ->setHref($this->getApplicationURI("public/{$id}/"))
+ ->setWorkflow(true));
+ }
}
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
@@ -50,6 +50,23 @@
}
+ public function didInitializeNewCredential(
+ PhabricatorUser $actor,
+ PassphraseCredential $credential) {
+ return $credential;
+ }
+
+ public function hasPublicKey() {
+ return false;
+ }
+
+ public function getPublicKey(
+ PhabricatorUser $viewer,
+ PassphraseCredential $credential) {
+ return null;
+ }
+
+
/* -( Passwords )---------------------------------------------------------- */
diff --git a/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHGeneratedKey.php b/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHGeneratedKey.php
new file mode 100644
--- /dev/null
+++ b/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHGeneratedKey.php
@@ -0,0 +1,36 @@
+<?php
+
+final class PassphraseCredentialTypeSSHGeneratedKey
+ extends PassphraseCredentialTypeSSHPrivateKey {
+
+ const CREDENTIAL_TYPE = 'ssh-generated-key';
+
+ public function getCredentialType() {
+ return self::CREDENTIAL_TYPE;
+ }
+
+ public function getCredentialTypeName() {
+ return pht('SSH Private Key (Generated)');
+ }
+
+ public function getCredentialTypeDescription() {
+ return pht('Generate an SSH keypair.');
+ }
+
+ public function getSecretLabel() {
+ return pht('Generated Key');
+ }
+
+ public function didInitializeNewCredential(
+ PhabricatorUser $actor,
+ PassphraseCredential $credential) {
+
+ $pair = PhabricatorSSHKeyGenerator::generateKeypair();
+ list($public_key, $private_key) = $pair;
+
+ $credential->attachSecret(new PhutilOpaqueEnvelope($private_key));
+
+ return $credential;
+ }
+
+}
diff --git a/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php b/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php
--- a/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php
+++ b/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php
@@ -9,4 +9,20 @@
return self::PROVIDES_TYPE;
}
+ public function hasPublicKey() {
+ return true;
+ }
+
+ public function getPublicKey(
+ PhabricatorUser $viewer,
+ PassphraseCredential $credential) {
+
+ $key = PassphraseSSHKey::loadFromPHID($credential->getPHID(), $viewer);
+ $file = $key->getKeyfileEnvelope();
+
+ list($stdout) = execx('ssh-keygen -y -f %P', $file);
+
+ return $stdout;
+ }
+
}
diff --git a/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php b/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php
--- a/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php
+++ b/src/applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php
@@ -33,4 +33,9 @@
return false;
}
+ public function hasPublicKey() {
+ // These have public keys, but they'd be cumbersome to extract.
+ return true;
+ }
+
}
diff --git a/src/applications/passphrase/keys/PassphraseSSHKey.php b/src/applications/passphrase/keys/PassphraseSSHKey.php
--- a/src/applications/passphrase/keys/PassphraseSSHKey.php
+++ b/src/applications/passphrase/keys/PassphraseSSHKey.php
@@ -15,10 +15,10 @@
public function getKeyfileEnvelope() {
$credential = $this->requireCredential();
- $text_type = PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE;
- if ($credential->getCredentialType() == $text_type) {
- // If the credential stores key text, write it out to a temporary file
- // so we can pass it to `ssh`.
+ $file_type = PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE;
+ if ($credential->getCredentialType() != $file_type) {
+ // If the credential does not store a file, write the key txt out to a
+ // temporary file so we can pass it to `ssh`.
if (!$this->keyFile) {
$temporary_file = new TempFile('passphrase-ssh-key');
diff --git a/src/applications/passphrase/storage/PassphraseCredential.php b/src/applications/passphrase/storage/PassphraseCredential.php
--- a/src/applications/passphrase/storage/PassphraseCredential.php
+++ b/src/applications/passphrase/storage/PassphraseCredential.php
@@ -25,6 +25,10 @@
->setEditPolicy($actor->getPHID());
}
+ public function getMonogram() {
+ return 'K'.$this->getID();
+ }
+
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 28, 5:10 AM (1 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7715226
Default Alt Text
D8515.id20197.diff (14 KB)
Attached To
Mode
D8515: Allow Passphrase to generate SSH keypairs and extact public keys from private keys
Attached
Detach File
Event Timeline
Log In to Comment