/* * CreateKeyDialog.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.common.vcs; import org.rstudio.core.client.files.FileSystemItem; import org.rstudio.core.client.widget.CaptionWithHelp; import org.rstudio.core.client.widget.FocusHelper; import org.rstudio.core.client.widget.MessageDialog; import org.rstudio.core.client.widget.ModalDialog; import org.rstudio.core.client.widget.Operation; import org.rstudio.core.client.widget.OperationWithInput; import org.rstudio.core.client.widget.ProgressIndicator; import org.rstudio.core.client.widget.ProgressOperationWithInput; import org.rstudio.core.client.widget.ShowContentDialog; import org.rstudio.studio.client.RStudioGinjector; import org.rstudio.studio.client.common.GlobalDisplay; import org.rstudio.studio.client.common.crypto.RSAEncrypt; import org.rstudio.studio.client.server.ServerError; import org.rstudio.studio.client.server.ServerRequestCallback; import com.google.gwt.core.client.GWT; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.CssResource; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; public class CreateKeyDialog extends ModalDialog<CreateKeyOptions> { public CreateKeyDialog(String rsaSshKeyPath, final VCSServerOperations server, final OperationWithInput<String> onCompleted) { super("Create RSA Key", new ProgressOperationWithInput<CreateKeyOptions>() { @Override public void execute(final CreateKeyOptions input, final ProgressIndicator indicator) { final ProgressOperationWithInput<CreateKeyOptions> thisOperation = this; indicator.onProgress("Creating RSA Key..."); RSAEncrypt.encrypt_ServerOnly( server, input.getPassphrase(), new RSAEncrypt.ResponseCallback() { @Override public void onSuccess(final String encryptedData) { // substitute encrypted data final CreateKeyOptions options = CreateKeyOptions.create( input.getPath(), input.getType(), encryptedData, input.getOverwrite()); // call server to create the key server.createSshKey( options, new ServerRequestCallback<CreateKeyResult>() { @Override public void onResponseReceived(CreateKeyResult res) { if (res.getFailedKeyExists()) { indicator.clearProgress(); confirmOverwriteKey( input.getPath(), new Operation() { @Override public void execute() { // re-execute with overwrite == true thisOperation.execute( CreateKeyOptions.create( options.getPath(), options.getType(), input.getPassphrase(), true), indicator); } }); } else { // close the dialog indicator.onCompleted(); // update the key path if (res.getExitStatus() == 0) onCompleted.execute(input.getPath()); else if (input.getOverwrite()) onCompleted.execute(null); // show the output new ShowContentDialog( "Create RSA Key", res.getOutput()).showModal(); } } @Override public void onError(ServerError error) { indicator.onError(error.getUserMessage()); } }); } @Override public void onFailure(ServerError error) { indicator.onError(error.getUserMessage()); } } ); } }); rsaSshKeyPath_ = FileSystemItem.createDir(rsaSshKeyPath); setOkButtonCaption("Create"); } @Override protected CreateKeyOptions collectInput() { if (!getPassphrase().equals(getConfirmPassphrase())) return null; else return CreateKeyOptions.create(rsaSshKeyPath_.getPath(), "rsa", getPassphrase(), false); } @Override protected boolean validate(CreateKeyOptions input) { if (input != null) { return true; } else { GlobalDisplay display = RStudioGinjector.INSTANCE.getGlobalDisplay(); if (!getPassphrase().equals(getConfirmPassphrase())) { display.showErrorMessage( "Non-Matching Passphrases", "The passphrase and passphrase confirmation do not match.", txtConfirmPassphrase_); } return false; } } @Override protected Widget createMainWidget() { Styles styles = RESOURCES.styles(); VerticalPanel panel = new VerticalPanel(); panel.addStyleName(styles.mainWidget()); VerticalPanel namePanel = new VerticalPanel(); namePanel.setWidth("100%"); // path CaptionWithHelp pathCaption = new CaptionWithHelp( "The RSA key will be created at:", "SSH/RSA key management", "rsa_key_help"); pathCaption.setIncludeVersionInfo(false); pathCaption.setWidth("100%"); namePanel.add(pathCaption); TextBox txtKeyPath = new TextBox(); txtKeyPath.addStyleName(styles.keyPathTextBox()); txtKeyPath.setReadOnly(true); txtKeyPath.setText(rsaSshKeyPath_.getPath()); txtKeyPath.setWidth("100%"); namePanel.add(txtKeyPath); panel.add(namePanel); HorizontalPanel passphrasePanel = new HorizontalPanel(); passphrasePanel.addStyleName(styles.newSection()); VerticalPanel passphrasePanel1 = new VerticalPanel(); Label passphraseLabel1 = new Label("Passphrase (optional):"); passphraseLabel1.addStyleName(styles.entryLabel()); passphrasePanel1.add(passphraseLabel1); txtPassphrase_ = new PasswordTextBox(); txtPassphrase_.addStyleName(styles.passphrase()); passphrasePanel1.add(txtPassphrase_); passphrasePanel.add(passphrasePanel1); VerticalPanel passphrasePanel2 = new VerticalPanel(); passphrasePanel2.addStyleName(styles.lastSection()); Label passphraseLabel2 = new Label("Confirm:"); passphraseLabel2.addStyleName(styles.entryLabel()); passphrasePanel2.add(passphraseLabel2); txtConfirmPassphrase_ = new PasswordTextBox(); txtConfirmPassphrase_.addStyleName(styles.passphraseConfirm()); passphrasePanel2.add(txtConfirmPassphrase_); passphrasePanel.add(passphrasePanel2); panel.add(passphrasePanel); return panel; } @Override protected void onLoad() { super.onLoad(); FocusHelper.setFocusDeferred(txtPassphrase_); } private static void confirmOverwriteKey(String path, Operation onConfirmed) { RStudioGinjector.INSTANCE.getGlobalDisplay().showYesNoMessage( MessageDialog.WARNING, "Key Already Exists", "An RSA key already exists at " + path + ". " + "Do you want to overwrite the existing key?", onConfirmed, false); } private String getPassphrase() { return txtPassphrase_.getText().trim(); } private String getConfirmPassphrase() { return txtConfirmPassphrase_.getText().trim(); } static interface Styles extends CssResource { String entryLabel(); String keyPathTextBox(); String mainWidget(); String newSection(); String lastSection(); String passphrase(); String passphraseConfirm(); } static interface Resources extends ClientBundle { @Source("CreateKeyDialog.css") Styles styles(); } static Resources RESOURCES = (Resources)GWT.create(Resources.class) ; public static void ensureStylesInjected() { RESOURCES.styles().ensureInjected(); } private TextBox txtPassphrase_; private TextBox txtConfirmPassphrase_; private final FileSystemItem rsaSshKeyPath_; }