blob: 0f282b6ee644490a2a85fcfa300dd63bbefcb3c2 [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.android.exportSignedPackage;
import com.intellij.ide.passwordSafe.PasswordSafe;
import com.intellij.ide.passwordSafe.PasswordSafeException;
import com.intellij.ide.wizard.CommitStepException;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.ui.components.JBCheckBox;
import org.jetbrains.android.compiler.artifact.ApkSigningSettingsForm;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUiUtil;
import org.jetbrains.android.util.AndroidUtils;
import javax.swing.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
/**
* @author Eugene.Kudelevsky
*/
class KeystoreStep extends ExportSignedPackageWizardStep implements ApkSigningSettingsForm {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.exportSignedPackage.KeystoreStep");
private static final String KEY_STORE_PASSWORD_KEY = "KEY_STORE_PASSWORD";
private static final String KEY_PASSWORD_KEY = "KEY_PASSWORD";
private JPanel myContentPanel;
private JPasswordField myKeyStorePasswordField;
private JPasswordField myKeyPasswordField;
private TextFieldWithBrowseButton.NoPathCompletion myKeyAliasField;
private JTextField myKeyStorePathField;
private JButton myCreateKeyStoreButton;
private JButton myLoadKeyStoreButton;
private JBCheckBox myRememberPasswordCheckBox;
private final ExportSignedPackageWizard myWizard;
public KeystoreStep(ExportSignedPackageWizard wizard) {
myWizard = wizard;
final Project project = wizard.getProject();
final GenerateSignedApkSettings settings = GenerateSignedApkSettings.getInstance(project);
myKeyStorePathField.setText(settings.KEY_STORE_PATH);
myKeyAliasField.setText(settings.KEY_ALIAS);
myRememberPasswordCheckBox.setSelected(settings.REMEMBER_PASSWORDS);
if (settings.REMEMBER_PASSWORDS) {
final PasswordSafe passwordSafe = PasswordSafe.getInstance();
try {
String password = passwordSafe.getPassword(project, KeystoreStep.class, KEY_STORE_PASSWORD_KEY);
if (password != null) {
myKeyStorePasswordField.setText(password);
}
password = passwordSafe.getPassword(project, KeystoreStep.class, KEY_PASSWORD_KEY);
if (password != null) {
myKeyPasswordField.setText(password);
}
}
catch (PasswordSafeException e) {
LOG.debug(e);
myKeyStorePasswordField.setText("");
myKeyPasswordField.setText("");
}
}
AndroidUiUtil.initSigningSettingsForm(project, this);
}
@Override
protected JComponent getPreferredFocusedComponent() {
if (myKeyStorePathField.getText().length() == 0) {
return myKeyStorePathField;
}
else if (myKeyStorePasswordField.getPassword().length == 0) {
return myKeyStorePasswordField;
}
else if (myKeyAliasField.getText().length() == 0) {
return myKeyAliasField;
}
else if (myKeyPasswordField.getPassword().length == 0) {
return myKeyPasswordField;
}
return null;
}
@Override
public JComponent getComponent() {
return myContentPanel;
}
@Override
public String getHelpId() {
return "reference.android.reference.extract.signed.package.specify.keystore";
}
@Override
protected void commitForNext() throws CommitStepException {
final String keyStoreLocation = myKeyStorePathField.getText().trim();
if (keyStoreLocation.length() == 0) {
throw new CommitStepException(AndroidBundle.message("android.export.package.specify.keystore.location.error"));
}
final char[] keyStorePassword = myKeyStorePasswordField.getPassword();
if (keyStorePassword.length == 0) {
throw new CommitStepException(AndroidBundle.message("android.export.package.specify.key.store.password.error"));
}
final String keyAlias = myKeyAliasField.getText().trim();
if (keyAlias.length() == 0) {
throw new CommitStepException(AndroidBundle.message("android.export.package.specify.key.alias.error"));
}
final char[] keyPassword = myKeyPasswordField.getPassword();
if (keyPassword.length == 0) {
throw new CommitStepException(AndroidBundle.message("android.export.package.specify.key.password.error"));
}
final KeyStore keyStore = loadKeyStore(new File(keyStoreLocation));
if (keyStore == null) {
throw new CommitStepException(AndroidBundle.message("android.export.package.keystore.error.title"));
}
loadKeyAndSaveToWizard(keyStore, keyAlias, keyPassword);
final Project project = myWizard.getProject();
final GenerateSignedApkSettings settings = GenerateSignedApkSettings.getInstance(project);
settings.KEY_STORE_PATH = keyStoreLocation;
settings.KEY_ALIAS = keyAlias;
final boolean rememberPasswords = myRememberPasswordCheckBox.isSelected();
settings.REMEMBER_PASSWORDS = rememberPasswords;
final PasswordSafe passwordSafe = PasswordSafe.getInstance();
try {
if (rememberPasswords) {
passwordSafe.storePassword(project, KeystoreStep.class, KEY_STORE_PASSWORD_KEY, new String(keyStorePassword));
passwordSafe.storePassword(project, KeystoreStep.class, KEY_PASSWORD_KEY, new String(keyPassword));
}
else {
passwordSafe.removePassword(project, KeystoreStep.class, KEY_STORE_PASSWORD_KEY);
passwordSafe.removePassword(project, KeystoreStep.class, KEY_PASSWORD_KEY);
}
}
catch (PasswordSafeException e) {
LOG.debug(e);
throw new CommitStepException("Cannot store passwords: " + e.getMessage());
}
}
private KeyStore loadKeyStore(File keystoreFile) throws CommitStepException {
final char[] password = myKeyStorePasswordField.getPassword();
FileInputStream fis = null;
AndroidUtils.checkPassword(password);
if (!keystoreFile.isFile()) {
throw new CommitStepException(AndroidBundle.message("android.cannot.find.file.error", keystoreFile.getPath()));
}
final KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
//noinspection IOResourceOpenedButNotSafelyClosed
fis = new FileInputStream(keystoreFile);
keyStore.load(fis, password);
}
catch (Exception e) {
throw new CommitStepException(e.getMessage());
}
finally {
if (fis != null) {
try {
fis.close();
}
catch (IOException ignored) {
}
}
Arrays.fill(password, '\0');
}
return keyStore;
}
private void loadKeyAndSaveToWizard(KeyStore keyStore, String alias, char[] keyPassword) throws CommitStepException {
KeyStore.PrivateKeyEntry entry;
try {
assert keyStore != null;
entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, new KeyStore.PasswordProtection(keyPassword));
}
catch (Exception e) {
throw new CommitStepException("Error: " + e.getMessage());
}
if (entry == null) {
throw new CommitStepException(AndroidBundle.message("android.extract.package.cannot.find.key.error", alias));
}
PrivateKey privateKey = entry.getPrivateKey();
Certificate certificate = entry.getCertificate();
if (privateKey == null || certificate == null) {
throw new CommitStepException(AndroidBundle.message("android.extract.package.cannot.find.key.error", alias));
}
myWizard.setPrivateKey(privateKey);
myWizard.setCertificate((X509Certificate)certificate);
}
@Override
public JButton getLoadKeyStoreButton() {
return myLoadKeyStoreButton;
}
@Override
public JTextField getKeyStorePathField() {
return myKeyStorePathField;
}
@Override
public JPanel getPanel() {
return myContentPanel;
}
@Override
public JButton getCreateKeyStoreButton() {
return myCreateKeyStoreButton;
}
@Override
public JPasswordField getKeyStorePasswordField() {
return myKeyStorePasswordField;
}
@Override
public TextFieldWithBrowseButton getKeyAliasField() {
return myKeyAliasField;
}
@Override
public JPasswordField getKeyPasswordField() {
return myKeyPasswordField;
}
}