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 @@ -1318,8 +1318,12 @@ 'PhabricatorAuthRegisterController' => 'applications/auth/controller/PhabricatorAuthRegisterController.php', 'PhabricatorAuthRevokeTokenController' => 'applications/auth/controller/PhabricatorAuthRevokeTokenController.php', 'PhabricatorAuthSSHKey' => 'applications/auth/storage/PhabricatorAuthSSHKey.php', + 'PhabricatorAuthSSHKeyController' => 'applications/auth/controller/PhabricatorAuthSSHKeyController.php', + 'PhabricatorAuthSSHKeyDeleteController' => 'applications/auth/controller/PhabricatorAuthSSHKeyDeleteController.php', + 'PhabricatorAuthSSHKeyEditController' => 'applications/auth/controller/PhabricatorAuthSSHKeyEditController.php', + 'PhabricatorAuthSSHKeyGenerateController' => 'applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php', 'PhabricatorAuthSSHKeyQuery' => 'applications/auth/query/PhabricatorAuthSSHKeyQuery.php', - 'PhabricatorAuthSSHPublicKey' => 'applications/auth/storage/PhabricatorAuthSSHPublicKey.php', + 'PhabricatorAuthSSHPublicKey' => 'applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php', 'PhabricatorAuthSession' => 'applications/auth/storage/PhabricatorAuthSession.php', 'PhabricatorAuthSessionEngine' => 'applications/auth/engine/PhabricatorAuthSessionEngine.php', 'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php', @@ -2249,6 +2253,7 @@ 'PhabricatorSSHKeyGenerator' => 'infrastructure/util/PhabricatorSSHKeyGenerator.php', 'PhabricatorSSHLog' => 'infrastructure/log/PhabricatorSSHLog.php', 'PhabricatorSSHPassthruCommand' => 'infrastructure/ssh/PhabricatorSSHPassthruCommand.php', + 'PhabricatorSSHPublicKeyInterface' => 'applications/auth/sshkey/PhabricatorSSHPublicKeyInterface.php', 'PhabricatorSSHWorkflow' => 'infrastructure/ssh/PhabricatorSSHWorkflow.php', 'PhabricatorSavedQuery' => 'applications/search/storage/PhabricatorSavedQuery.php', 'PhabricatorSavedQueryQuery' => 'applications/search/query/PhabricatorSavedQueryQuery.php', @@ -4386,6 +4391,10 @@ 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', ), + 'PhabricatorAuthSSHKeyController' => 'PhabricatorAuthController', + 'PhabricatorAuthSSHKeyDeleteController' => 'PhabricatorAuthSSHKeyController', + 'PhabricatorAuthSSHKeyEditController' => 'PhabricatorAuthSSHKeyController', + 'PhabricatorAuthSSHKeyGenerateController' => 'PhabricatorAuthSSHKeyController', 'PhabricatorAuthSSHKeyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthSSHPublicKey' => 'Phobject', 'PhabricatorAuthSession' => array( @@ -5608,6 +5617,7 @@ 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorSSHPublicKeyInterface', ), 'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField', 'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions', diff --git a/src/applications/auth/application/PhabricatorAuthApplication.php b/src/applications/auth/application/PhabricatorAuthApplication.php --- a/src/applications/auth/application/PhabricatorAuthApplication.php +++ b/src/applications/auth/application/PhabricatorAuthApplication.php @@ -109,6 +109,12 @@ => 'PhabricatorAuthDowngradeSessionController', 'multifactor/' => 'PhabricatorAuthNeedsMultiFactorController', + 'sshkey/' => array( + 'generate/' => 'PhabricatorAuthSSHKeyGenerateController', + 'upload/' => 'PhabricatorAuthSSHKeyEditController', + 'edit/(?P\d+)/' => 'PhabricatorAuthSSHKeyEditController', + 'delete/(?P\d+)/' => 'PhabricatorAuthSSHKeyDeleteController', + ), ), '/oauth/(?P\w+)/login/' diff --git a/src/applications/auth/controller/PhabricatorAuthSSHKeyController.php b/src/applications/auth/controller/PhabricatorAuthSSHKeyController.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/controller/PhabricatorAuthSSHKeyController.php @@ -0,0 +1,33 @@ +getViewer(); + + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($object_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$object) { + return null; + } + + // If this kind of object can't have SSH keys, don't let the viewer + // add them. + if (!($object instanceof PhabricatorSSHPublicKeyInterface)) { + return null; + } + + return id(new PhabricatorAuthSSHKey()) + ->setObjectPHID($object_phid) + ->attachObject($object); + } + +} diff --git a/src/applications/auth/controller/PhabricatorAuthSSHKeyDeleteController.php b/src/applications/auth/controller/PhabricatorAuthSSHKeyDeleteController.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/controller/PhabricatorAuthSSHKeyDeleteController.php @@ -0,0 +1,48 @@ +getViewer(); + + $key = id(new PhabricatorAuthSSHKeyQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$key) { + return new Aphront404Response(); + } + + $cancel_uri = $key->getObject()->getSSHPublicKeyManagementURI($viewer); + + $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( + $viewer, + $request, + $cancel_uri); + + if ($request->isFormPost()) { + // TODO: It would be nice to write an edge transaction here or something. + $key->delete(); + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } + + $name = phutil_tag('strong', array(), $key->getName()); + + return $this->newDialog() + ->setTitle(pht('Really delete SSH Public Key?')) + ->appendParagraph( + pht( + 'The key "%s" will be permanently deleted, and you will not longer '. + 'be able to use the corresponding private key to authenticate.', + $name)) + ->addSubmitButton(pht('Delete Public Key')) + ->addCancelButton($cancel_uri); + } + +} diff --git a/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php b/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/controller/PhabricatorAuthSSHKeyEditController.php @@ -0,0 +1,127 @@ +getViewer(); + + $id = $request->getURIData('id'); + if ($id) { + $key = id(new PhabricatorAuthSSHKeyQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$key) { + return new Aphront404Response(); + } + + $is_new = false; + } else { + $key = $this->newKeyForObjectPHID($request->getStr('objectPHID')); + if (!$key) { + return new Aphront404Response(); + } + $is_new = true; + } + + $cancel_uri = $key->getObject()->getSSHPublicKeyManagementURI($viewer); + + $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( + $viewer, + $request, + $cancel_uri); + + $v_name = $key->getName(); + $e_name = strlen($v_name) ? null : true; + + $v_key = $key->getEntireKey(); + $e_key = strlen($v_key) ? null : true; + + $errors = array(); + if ($request->isFormPost()) { + $v_name = $request->getStr('name'); + $v_key = $request->getStr('key'); + + if (!strlen($v_name)) { + $errors[] = pht('You must provide a name for this public key.'); + $e_name = pht('Required'); + } else { + $key->setName($v_name); + } + + if (!strlen($v_key)) { + $errors[] = pht('You must provide a public key.'); + $e_key = pht('Required'); + } else { + try { + $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($v_key); + + $type = $public_key->getType(); + $body = $public_key->getBody(); + $comment = $public_key->getComment(); + + $key->setKeyType($type); + $key->setKeyBody($body); + $key->setKeyComment($comment); + + $e_key = null; + } catch (Exception $ex) { + $e_key = pht('Invalid'); + $errors[] = $ex->getMessage(); + } + } + + if (!$errors) { + try { + $key->save(); + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } catch (Exception $ex) { + $e_key = pht('Duplicate'); + $errors[] = pht( + 'This public key is already associated with another user or '. + 'device. Each key must unambiguously identify a single unique '. + 'owner.'); + } + } + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Name')) + ->setName('name') + ->setError($e_name) + ->setValue($v_name)) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel(pht('Public Key')) + ->setName('key') + ->setValue($v_key) + ->setError($e_key)); + + if ($is_new) { + $title = pht('Upload SSH Public Key'); + $save_button = pht('Upload Public Key'); + $form->addHiddenInput('objectPHID', $key->getObject()->getPHID()); + } else { + $title = pht('Edit SSH Public Key'); + $save_button = pht('Save Changes'); + } + + return $this->newDialog() + ->setTitle($title) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->setErrors($errors) + ->appendForm($form) + ->addSubmitButton($save_button) + ->addCancelButton($cancel_uri); + } + +} diff --git a/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php b/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/controller/PhabricatorAuthSSHKeyGenerateController.php @@ -0,0 +1,90 @@ +getViewer(); + + $key = $this->newKeyForObjectPHID($request->getStr('objectPHID')); + if (!$key) { + return new Aphront404Response(); + } + + $cancel_uri = $key->getObject()->getSSHPublicKeyManagementURI($viewer); + + $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( + $viewer, + $request, + $cancel_uri); + + if ($request->isFormPost()) { + $keys = PhabricatorSSHKeyGenerator::generateKeypair(); + list($public_key, $private_key) = $keys; + + $file = PhabricatorFile::buildFromFileDataOrHash( + $private_key, + array( + 'name' => 'id_rsa_phabricator.key', + 'ttl' => time() + (60 * 10), + 'viewPolicy' => $viewer->getPHID(), + )); + + $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($public_key); + + $type = $public_key->getType(); + $body = $public_key->getBody(); + + $key + ->setName('id_rsa_phabricator') + ->setKeyType($type) + ->setKeyBody($body) + ->setKeyComment(pht('Generated')) + ->save(); + + // NOTE: We're disabling workflow on submit so the download works. We're + // disabling workflow on cancel so the page reloads, showing the new + // key. + + return $this->newDialog() + ->setTitle(pht('Download Private Key')) + ->setDisableWorkflowOnCancel(true) + ->setDisableWorkflowOnSubmit(true) + ->setSubmitURI($file->getDownloadURI()) + ->appendParagraph( + pht( + 'A keypair has been generated, and the public key has been '. + 'added as a recognized key. Use the button below to download '. + 'the private key.')) + ->appendParagraph( + pht( + 'After you download the private key, it will be destroyed. '. + 'You will not be able to retrieve it if you lose your copy.')) + ->addSubmitButton(pht('Download Private Key')) + ->addCancelButton($cancel_uri, pht('Done')); + } + + try { + PhabricatorSSHKeyGenerator::assertCanGenerateKeypair(); + + return $this->newDialog() + ->setTitle(pht('Generate New Keypair')) + ->addHiddenInput('objectPHID', $key->getObject()->getPHID()) + ->appendParagraph( + pht( + 'This workflow will generate a new SSH keypair, add the public '. + 'key, and let you download the private key.')) + ->appendParagraph( + pht( + 'Phabricator will not retain a copy of the private key.')) + ->addSubmitButton(pht('Generate New Keypair')) + ->addCancelButton($cancel_uri); + } catch (Exception $ex) { + return $this->newDialog() + ->setTitle(pht('Unable to Generate Keys')) + ->appendParagraph($ex->getMessage()) + ->addCancelButton($cancel_uri); + } + } + +} diff --git a/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php b/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php --- a/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php +++ b/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php @@ -50,10 +50,14 @@ foreach ($keys as $key => $ssh_key) { $object = idx($objects, $ssh_key->getObjectPHID()); - if (!$object) { + + // We must have an object, and that object must be a valid object for + // SSH keys. + if (!$object || !($object instanceof PhabricatorSSHPublicKeyInterface)) { unset($keys[$key]); continue; } + $ssh_key->attachObject($object); } diff --git a/src/applications/auth/storage/PhabricatorAuthSSHPublicKey.php b/src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php rename from src/applications/auth/storage/PhabricatorAuthSSHPublicKey.php rename to src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php diff --git a/src/applications/auth/sshkey/PhabricatorSSHPublicKeyInterface.php b/src/applications/auth/sshkey/PhabricatorSSHPublicKeyInterface.php new file mode 100644 --- /dev/null +++ b/src/applications/auth/sshkey/PhabricatorSSHPublicKeyInterface.php @@ -0,0 +1,14 @@ +assertAttached($this->object); } - public function attachObject($object) { + public function attachObject(PhabricatorSSHPublicKeyInterface $object) { $this->object = $object; return $this; } diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -9,7 +9,8 @@ PhutilPerson, PhabricatorPolicyInterface, PhabricatorCustomFieldInterface, - PhabricatorDestructibleInterface { + PhabricatorDestructibleInterface, + PhabricatorSSHPublicKeyInterface { const SESSION_TABLE = 'phabricator_session'; const NAMETOKEN_TABLE = 'user_nametoken'; @@ -928,4 +929,18 @@ } +/* -( PhabricatorSSHPublicKeyInterface )----------------------------------- */ + + + public function getSSHPublicKeyManagementURI(PhabricatorUser $viewer) { + if ($viewer->getPHID() == $this->getPHID()) { + // If the viewer is managing their own keys, take them to the normal + // panel. + return '/settings/panel/ssh/'; + } else { + // Otherwise, take them to the administrative panel for this user. + return '/settings/'.$this->getID().'/panel/ssh/'; + } + } + } diff --git a/src/applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php b/src/applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php --- a/src/applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php +++ b/src/applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php @@ -24,138 +24,6 @@ } public function processRequest(AphrontRequest $request) { - $viewer = $request->getUser(); - $user = $this->getUser(); - - $generate = $request->getStr('generate'); - if ($generate) { - return $this->processGenerate($request); - } - - $edit = $request->getStr('edit'); - $delete = $request->getStr('delete'); - if (!$edit && !$delete) { - return $this->renderKeyListView($request); - } - - $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( - $viewer, - $request, - $this->getPanelURI()); - - $id = nonempty($edit, $delete); - if ($id && (int)$id) { - $key = id(new PhabricatorAuthSSHKeyQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$key) { - return new Aphront404Response(); - } - } else { - $key = id(new PhabricatorAuthSSHKey()) - ->setObjectPHID($user->getPHID()); - } - - if ($delete) { - return $this->processDelete($request, $key); - } - - $e_name = true; - $e_key = true; - $errors = array(); - $entire_key = $key->getEntireKey(); - if ($request->isFormPost()) { - $key->setName($request->getStr('name')); - $entire_key = $request->getStr('key'); - - if (!strlen($entire_key)) { - $errors[] = pht('You must provide an SSH Public Key.'); - $e_key = pht('Required'); - } else { - - try { - $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($entire_key); - - $type = $public_key->getType(); - $body = $public_key->getBody(); - $comment = $public_key->getComment(); - - $key->setKeyType($type); - $key->setKeyBody($body); - $key->setKeyComment($comment); - - $e_key = null; - } catch (Exception $ex) { - $e_key = pht('Invalid'); - $errors[] = $ex->getMessage(); - } - } - - if (!strlen($key->getName())) { - $errors[] = pht('You must name this public key.'); - $e_name = pht('Required'); - } else { - $e_name = null; - } - - if (!$errors) { - try { - $key->save(); - return id(new AphrontRedirectResponse()) - ->setURI($this->getPanelURI()); - } catch (AphrontDuplicateKeyQueryException $ex) { - $e_key = pht('Duplicate'); - $errors[] = pht('This public key is already associated with a user '. - 'account.'); - } - } - } - - $is_new = !$key->getID(); - - if ($is_new) { - $header = pht('Add New SSH Public Key'); - $save = pht('Add Key'); - } else { - $header = pht('Edit SSH Public Key'); - $save = pht('Save Changes'); - } - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->addHiddenInput('edit', $is_new ? 'true' : $key->getID()) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Name')) - ->setName('name') - ->setValue($key->getName()) - ->setError($e_name)) - ->appendChild( - id(new AphrontFormTextAreaControl()) - ->setLabel(pht('Public Key')) - ->setName('key') - ->setValue($entire_key) - ->setError($e_key)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($this->getPanelURI()) - ->setValue($save)); - - $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText($header) - ->setFormErrors($errors) - ->setForm($form); - - return $form_box; - } - - private function renderKeyListView(AphrontRequest $request) { $user = $this->getUser(); $viewer = $request->getUser(); @@ -167,10 +35,11 @@ $rows = array(); foreach ($keys as $key) { $rows[] = array( - phutil_tag( + javelin_tag( 'a', array( - 'href' => $this->getPanelURI('?edit='.$key->getID()), + 'href' => '/auth/sshkey/edit/'.$key->getID().'/', + 'sigil' => 'workflow', ), $key->getName()), $key->getKeyComment(), @@ -180,7 +49,7 @@ javelin_tag( 'a', array( - 'href' => $this->getPanelURI('?delete='.$key->getID()), + 'href' => '/auth/sshkey/delete/'.$key->getID().'/', 'class' => 'small grey button', 'sigil' => 'workflow', ), @@ -216,7 +85,8 @@ ->setIconFont('fa-upload'); $upload_button = id(new PHUIButtonView()) ->setText(pht('Upload Public Key')) - ->setHref($this->getPanelURI('?edit=true')) + ->setHref('/auth/sshkey/upload/?objectPHID='.$user->getPHID()) + ->setWorkflow(true) ->setTag('a') ->setIcon($upload_icon); @@ -231,7 +101,7 @@ ->setIconFont('fa-lock'); $generate_button = id(new PHUIButtonView()) ->setText(pht('Generate Keypair')) - ->setHref($this->getPanelURI('?generate=true')) + ->setHref('/auth/sshkey/generate/?objectPHID='.$user->getPHID()) ->setTag('a') ->setWorkflow(true) ->setDisabled(!$can_generate) @@ -247,143 +117,4 @@ return $panel; } - private function processDelete( - AphrontRequest $request, - PhabricatorAuthSSHKey $key) { - - $viewer = $request->getUser(); - $user = $this->getUser(); - - $name = phutil_tag('strong', array(), $key->getName()); - - if ($request->isDialogFormPost()) { - $key->delete(); - return id(new AphrontReloadResponse()) - ->setURI($this->getPanelURI()); - } - - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->addHiddenInput('delete', $key->getID()) - ->setTitle(pht('Really delete SSH Public Key?')) - ->appendChild(phutil_tag('p', array(), pht( - 'The key "%s" will be permanently deleted, and you will not longer be '. - 'able to use the corresponding private key to authenticate.', - $name))) - ->addSubmitButton(pht('Delete Public Key')) - ->addCancelButton($this->getPanelURI()); - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - - private function processGenerate(AphrontRequest $request) { - $user = $this->getUser(); - $viewer = $request->getUser(); - - $token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession( - $viewer, - $request, - $this->getPanelURI()); - - - $is_self = ($user->getPHID() == $viewer->getPHID()); - - if ($request->isFormPost()) { - $keys = PhabricatorSSHKeyGenerator::generateKeypair(); - list($public_key, $private_key) = $keys; - - $file = PhabricatorFile::buildFromFileDataOrHash( - $private_key, - array( - 'name' => 'id_rsa_phabricator.key', - 'ttl' => time() + (60 * 10), - 'viewPolicy' => $viewer->getPHID(), - )); - - $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($public_key); - - $type = $public_key->getType(); - $body = $public_key->getBody(); - - $key = id(new PhabricatorAuthSSHKey()) - ->setObjectPHID($user->getPHID()) - ->setName('id_rsa_phabricator') - ->setKeyType($type) - ->setKeyBody($body) - ->setKeyComment(pht('Generated')) - ->save(); - - // NOTE: We're disabling workflow on submit so the download works. We're - // disabling workflow on cancel so the page reloads, showing the new - // key. - - if ($is_self) { - $what_happened = pht( - 'The public key has been associated with your Phabricator '. - 'account. Use the button below to download the private key.'); - } else { - $what_happened = pht( - 'The public key has been associated with the %s account. '. - 'Use the button below to download the private key.', - phutil_tag('strong', array(), $user->getUsername())); - } - - $dialog = id(new AphrontDialogView()) - ->setTitle(pht('Download Private Key')) - ->setUser($viewer) - ->setDisableWorkflowOnCancel(true) - ->setDisableWorkflowOnSubmit(true) - ->setSubmitURI($file->getDownloadURI()) - ->appendParagraph( - pht( - 'Successfully generated a new keypair.')) - ->appendParagraph($what_happened) - ->appendParagraph( - pht( - 'After you download the private key, it will be destroyed. '. - 'You will not be able to retrieve it if you lose your copy.')) - ->addSubmitButton(pht('Download Private Key')) - ->addCancelButton($this->getPanelURI(), pht('Done')); - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->addCancelButton($this->getPanelURI()); - - try { - PhabricatorSSHKeyGenerator::assertCanGenerateKeypair(); - - if ($is_self) { - $explain = pht( - 'This will generate an SSH keypair, associate the public key '. - 'with your account, and let you download the private key.'); - } else { - $explain = pht( - 'This will generate an SSH keypair, associate the public key with '. - 'the %s account, and let you download the private key.', - phutil_tag('strong', array(), $user->getUsername())); - } - - $dialog - ->addHiddenInput('generate', true) - ->setTitle(pht('Generate New Keypair')) - ->appendParagraph($explain) - ->appendParagraph( - pht( - 'Phabricator will not retain a copy of the private key.')) - ->addSubmitButton(pht('Generate Keypair')); - } catch (Exception $ex) { - $dialog - ->setTitle(pht('Unable to Generate Keys')) - ->appendParagraph($ex->getMessage()); - } - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - }