diff options
Diffstat (limited to 'src/plugins/certmanager/src')
83 files changed, 18275 insertions, 0 deletions
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java new file mode 100644 index 0000000..156c5f3 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/CertificateManagerActivator.java @@ -0,0 +1,146 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager;
+
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class CertificateManagerActivator extends AbstractUIPlugin
+{
+
+ public static final String PLUGIN_ID = "com.motorolamobility.studio.android.certmanager"; //$NON-NLS-1$
+
+ public static final String UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID = PLUGIN_ID
+ + ".unsign_external_pkg_wiz";
+
+ public static final String REMOVE_SIGNATURE_WIZ_BAN = "icons/wizban/unsign_package_wiz.png";
+
+ public static final String SIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID = PLUGIN_ID
+ + ".sign_external_pkg_wiz";
+
+ public static final String SIGNATURE_WIZ_BAN = "icons/wizban/sign_package_wiz.png";
+
+ /**
+ * The manifest version
+ */
+ public static final String MANIFEST_VERSION = "1.0";
+
+ /**
+ * Manifest attribute created by
+ */
+ public static final String CREATED_BY_FIELD = "Created-By";
+
+ /**
+ * Value of Created by attribute
+ */
+ public static final String CREATED_BY_FIELD_VALUE = "MOTODEV Studio for Android";
+
+ /**
+ * Package metainf directory name
+ */
+ public static final String METAFILES_DIR = "META-INF";
+
+ /**
+ * The package manifest file name
+ */
+ public static final String MANIFEST_FILE_NAME = "MANIFEST.MF";
+
+ /**
+ * Jar separator
+ */
+ public static final String JAR_SEPARATOR = "/";
+
+ /**
+ * Prefix to be used in temp files.
+ * */
+ public static final String TEMP_FILE_PREFIX = "tmppkg_";
+
+ /**
+ * The package extension.
+ */
+ public static final String PACKAGE_EXTENSION = "apk";
+
+ /**
+ * The default package destination extension
+ */
+ public static final String PACKAGE_PROJECT_DESTINATION = "dist";
+
+ // The shared instance
+ private static CertificateManagerActivator plugin;
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception
+ {
+ StudioLogger.debug(CertificateManagerActivator.class,
+ "Starting MOTODEV Studio for Android Key Manager Plugin...");
+
+ super.start(context);
+ plugin = this;
+
+ StudioLogger.debug(CertificateManagerActivator.class,
+ "MOTODEV Studio for Android Key Manager Plugin started.");
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception
+ {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static CertificateManagerActivator getDefault()
+ {
+ return plugin;
+ }
+
+ /**
+ * The certificate manager plugin declares one view that is used to show the keystores.
+ * */
+ public static KeystoreManagerView getKeyStoremManagerView()
+ {
+ IViewPart view = EclipseUtils.getActiveView(KeystoreManagerView.ID);
+
+ if (view instanceof KeystoreManagerView)
+ {
+ return (KeystoreManagerView) view;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java new file mode 100644 index 0000000..358c511 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/AbstractHandler2.java @@ -0,0 +1,63 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This abstract handler adds convenient methods, like methods to retrieve the current selection.
+ */
+public abstract class AbstractHandler2 extends AbstractHandler implements IHandler2
+{
+
+ /**
+ * Retrieves the list of selected nodes.
+ * */
+ @SuppressWarnings("unchecked")
+ protected List<ITreeNode> getSelection()
+ {
+ List<ITreeNode> selectedNodes = new ArrayList<ITreeNode>(1);
+ ISelection selection =
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService()
+ .getSelection();
+ if (selection instanceof IStructuredSelection)
+ {
+ IStructuredSelection treeSelection = (IStructuredSelection) selection;
+ List<Object> selectedElements = treeSelection.toList();
+
+ for (Object selectedObject : selectedElements)
+ {
+ if (selectedObject instanceof ITreeNode)
+ {
+ selectedNodes.add((ITreeNode) selectedObject);
+ }
+ }
+ }
+
+ return selectedNodes;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java new file mode 100644 index 0000000..925a69d --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/BackupHandler.java @@ -0,0 +1,265 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.BackupDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Handler to execute the backup wizard.
+ * */
+public class BackupHandler extends AbstractHandler2 implements IHandler
+{
+
+ public static final String KS_TYPES_FILENAME = "KsTypes.csv"; //$NON-NLS-1$
+
+ private static final String KEYSTORE_EXT = ".keystore"; //$NON-NLS-1$
+
+ private static Date lastBackupDate = new Date();
+
+ private final Calendar cal = GregorianCalendar.getInstance();
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ BackupDialog dialog =
+ new BackupDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
+ try
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ List<String> initialInputList = new ArrayList<String>(keyStores.size());
+ for (int i = 0; i < keyStores.size(); i++)
+ {
+ boolean insert = true;
+ IKeyStore keyStore = keyStores.get(i);
+ if (keyStore instanceof ITreeNode)
+ {
+ ITreeNode ksNode = (ITreeNode) keyStore;
+ IStatus nodeStatus = ksNode.getNodeStatus();
+ if (!nodeStatus.isOK()
+ && (nodeStatus.getCode() == IKeyStore.WRONG_KEYSTORE_TYPE_ERROR_CODE))
+ {
+ insert = false;
+ }
+ }
+ if (insert)
+ {
+ initialInputList.add(keyStore.getFile().getAbsolutePath());
+ }
+ }
+
+ dialog.setInput(initialInputList.toArray(new String[initialInputList.size()]));
+ dialog.selectKeyStores(getSelection());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ throw new ExecutionException(e.getLocalizedMessage());
+ }
+
+ int diagReturn = dialog.open();
+ if (diagReturn == Dialog.OK)
+ {
+ File archiveFile = dialog.getArchiveFile();
+ List<String> selectedKeyStores = dialog.getSelectedKeyStores();
+ if (FileUtil.canWrite(archiveFile))
+ {
+ try
+ {
+ updateBackupDate(selectedKeyStores);
+ createZipArchive(archiveFile, selectedKeyStores);
+
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupHandler_Error_BackUp_Title,
+ CertificateManagerNLS.BackupHandler_Error_Setting_Date);
+ }
+ catch (IOException e)
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupHandler_Error_BackUp_Title, NLS.bind(
+ CertificateManagerNLS.BackupHandler_Error_Writing_Archive,
+ archiveFile));
+ }
+ }
+ else
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupHandler_Error_BackUp_Title, NLS.bind(
+ CertificateManagerNLS.BackupHandler_Error_Writing_Archive,
+ archiveFile));
+ }
+
+ }
+ return null;
+ }
+
+ private void updateBackupDate(List<String> selectedKeyStores) throws KeyStoreManagerException
+ {
+ KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ Long lastDateInMillis = cal.getTimeInMillis();
+ lastBackupDate.setTime(lastDateInMillis);
+
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (selectedKeyStores.contains(keyStore.getFile().getAbsolutePath()))
+ {
+ keyStore.setLastBackupDate(lastBackupDate);
+ }
+ }
+
+ }
+
+ private void createZipArchive(File zipFile, List<String> filePaths) throws IOException,
+ KeyStoreManagerException
+ {
+ ZipOutputStream zos = null;
+ FileInputStream in = null;
+ try
+ {
+ zos = new ZipOutputStream(new FileOutputStream(zipFile));
+ Iterator<String> it = filePaths.iterator();
+ List<String> entriesNames = new ArrayList<String>(filePaths.size());
+ Properties typeProperties = new Properties();
+
+ int nameSuffix = 1;
+ while (it.hasNext())
+ {
+ String keyStore = it.next();
+ File keyStoreFile = new File(keyStore);
+ if (keyStoreFile.exists())
+ {
+ String entryName = keyStoreFile.getName();
+ while (entriesNames.contains(entryName))
+ {
+ if (entryName.toLowerCase().endsWith(KEYSTORE_EXT))
+ {
+ entryName =
+ entryName
+ .replace(KEYSTORE_EXT, "_" + nameSuffix + KEYSTORE_EXT); //$NON-NLS-1$
+ }
+ else
+ {
+ entryName = entryName.concat(Integer.toString(nameSuffix));
+ }
+ nameSuffix++;
+ }
+ putKsType(typeProperties, entryName, keyStore);
+ ZipEntry zipEntry = new ZipEntry(entryName);
+ zos.putNextEntry(zipEntry);
+ entriesNames.add(entryName);
+
+ byte[] buf = new byte[1024 * 4];
+ int len;
+ in = new FileInputStream(keyStoreFile);
+ try
+ {
+ while ((len = in.read(buf)) > 0)
+ {
+ zos.write(buf, 0, len);
+ }
+ }
+ finally
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ zos.flush();
+ }
+ }
+ zos.putNextEntry(new ZipEntry(KS_TYPES_FILENAME));
+ putLastBackupDate(typeProperties);
+ typeProperties.store(zos, "KeyStore types"); //$NON-NLS-1$
+ }
+ finally
+ {
+ if (zos != null)
+ {
+ try
+ {
+ zos.flush();
+ zos.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close steam while creating zip archive. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+
+ private void putKsType(Properties properties, String entryName, String filePaths)
+ throws KeyStoreManagerException
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ String keyStorePath = keyStore.getFile().getAbsolutePath();
+ if (filePaths.contains(keyStorePath))
+ {
+ String type = keyStore.getType();
+ if (type != null)
+ {
+ properties.put(entryName, type);
+ }
+ break;
+ }
+ }
+
+ }
+
+ private void putLastBackupDate(Properties properties)
+ {
+ Long time = lastBackupDate.getTime();
+ String timeString = time.toString();
+ properties.put("lastBackupDate", timeString);
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java new file mode 100644 index 0000000..e50aeac --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CertificatePropertiesHandler.java @@ -0,0 +1,69 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.composite.KeyPropertiesBlock;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.CertificateInfoDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This class implements the command to display certificate properties
+ * */
+public class CertificatePropertiesHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStoreEntry)
+ {
+ final EntryNode keyStoreEntry = (EntryNode) node;
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
+ Shell shell = ww.getShell();
+
+ CertificateInfoDialog dialog =
+ new CertificateInfoDialog(shell, new KeyPropertiesBlock(),
+ keyStoreEntry);
+
+ dialog.open();
+ }
+ });
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java new file mode 100644 index 0000000..794831b --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangeKeyStoreTypeHandler.java @@ -0,0 +1,88 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.io.File;
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.importks.ConvertKeyStoreTypeDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Handler to execute the change keystore type wizard.
+ * */
+public class ChangeKeyStoreTypeHandler extends AbstractHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStore)
+ {
+ ConvertKeyStoreTypeDialog dialog =
+ new ConvertKeyStoreTypeDialog(PlatformUI.getWorkbench()
+ .getModalDialogShellProvider().getShell(), (IKeyStore) node);
+ int diagStatus = dialog.open();
+ if (diagStatus == Dialog.OK)
+ {
+ IKeyStore keyStore = dialog.getKeyStore();
+ String newType = dialog.getNewType();
+ Map<String, String> aliases = dialog.getAliases();
+ String password = dialog.getKeystorePassword();
+
+ File keyStoreFile = keyStore.getFile();
+ try
+ {
+ if (password != null)
+ {
+ //user entered some password
+ KeyStoreUtils.changeKeyStoreType(keyStoreFile, password.toCharArray(),
+ keyStore.getType(), newType, aliases);
+ keyStore.setType(newType);
+ keyStore.forceReload(password.toCharArray(), false);
+ KeyStoreModelEventManager.getInstance().fireEvent((ITreeNode) keyStore,
+ EventType.UPDATE);
+
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ }
+ catch (InvalidPasswordException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java new file mode 100644 index 0000000..19c1574 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeyHandler.java @@ -0,0 +1,186 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.security.KeyStore;
+import java.security.KeyStore.Entry;
+import java.security.UnrecoverableKeyException;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.window.Window;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.ui.PasswordInputDialog;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class changes the password of a key/certificate from the tree of the {@link KeystoreManagerView}
+ * */
+public class ChangePasswordKeyHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode entry = getSelection().get(0);
+
+ if (entry instanceof EntryNode)
+ {
+ //must enter old and new password
+ KeyStoreNode keyStoreNode = (KeyStoreNode) entry.getParent();
+ PasswordProvider passwordProvider = new PasswordProvider(keyStoreNode.getFile());
+ EntryNode entryNode = (EntryNode) entry;
+
+ PasswordInputDialog passwordInputDialog = null;
+
+ boolean cancelledOrChangedPassword = false;
+
+ do
+ {
+ passwordInputDialog =
+ new PasswordInputDialog(PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getShell(),
+ CertificateManagerNLS.PasswordInput_EnterOldKeyPasssword_Message,
+ true, null, EntryNode.KEY_PASSWORD_MIN_SIZE);
+ if (passwordInputDialog.open() == Window.OK)
+ {
+ String newPassword = passwordInputDialog.getNewPassword();
+ String oldPassword = passwordInputDialog.getOldPassword();
+
+ if ((newPassword != null) && (oldPassword != null))
+ {
+ try
+ {
+ Entry keyEntry = entryNode.getKeyEntry(oldPassword);
+ if (keyEntry != null)
+ {
+ boolean tryAgain = false;
+ boolean useSavedPass = true;
+ String keystorePassword = null;
+ KeyStore keyStore = null;
+ do
+ {
+ if (tryAgain)
+ {
+ useSavedPass = false;
+ }
+ keystorePassword =
+ passwordProvider
+ .getKeyStorePassword(true, useSavedPass);
+ tryAgain = false;
+ if (keystorePassword != null)
+ {
+ try
+ {
+ if (keyStoreNode.isPasswordValid(keystorePassword))
+ {
+ keyStore =
+ keyStoreNode.getKeyStore(keystorePassword);
+ }
+ else
+ {
+ tryAgain = true;
+ }
+ }
+ catch (InvalidPasswordException e)
+ {
+ tryAgain = true;
+ }
+ }
+ }
+ while (tryAgain);
+ if (keyStore != null)
+ {
+ KeyStoreUtils.changeEntryPassword(keyStore,
+ keystorePassword.toCharArray(), keyStoreNode.getFile(),
+ entryNode.getAlias(), keyEntry,
+ newPassword.toCharArray());
+
+ //delete old save password - if there is one
+ if (passwordProvider.isPasswordSaved(entryNode.getAlias()))
+ {
+ passwordProvider.deleteSavedPassword(entryNode.getAlias());
+ }
+
+ if (passwordInputDialog.needToStorePassword())
+ {
+ //store new password at provider
+ passwordProvider.savePassword(entryNode.getAlias(),
+ newPassword);
+ }
+
+ //success
+ cancelledOrChangedPassword = true;
+ EclipseUtils.showInformationDialog(
+ CertificateManagerNLS.PasswordChanged_Info_Title,
+ CertificateManagerNLS.PasswordChanged_KeyInfo_Message);
+
+ //update tooltip and image
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode,
+ EventType.UPDATE);
+ }
+ }
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ //error - notify on screen
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeyHandler_Error_WrongOldKeyPassword,
+ CertificateManagerNLS.ChangePasswordKeyHandler_Wrong_Key_Password);
+ }
+ catch (Exception e)
+ {
+ //error - notify on screen
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeyHandler_Error_WrongOldKeyPassword,
+ e.getMessage());
+ }
+ }
+ }
+ else
+ {
+ //user cancelled screen
+ cancelledOrChangedPassword = true;
+ }
+
+ }
+ while (!cancelledOrChangedPassword);
+
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java new file mode 100644 index 0000000..9b1948b --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ChangePasswordKeystoreHandler.java @@ -0,0 +1,157 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.security.KeyStore;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.ui.PasswordInputDialog;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class deletes the keystore from the tree of the {@link KeystoreManagerView}
+ * */
+public class ChangePasswordKeystoreHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof KeyStoreNode)
+ {
+ KeyStoreNode keyStoreNode = (KeyStoreNode) node;
+ PasswordProvider passwordProvider = new PasswordProvider(keyStoreNode.getFile());
+
+ //must enter old and new password
+ PasswordInputDialog passwordInputDialog = null;
+
+ boolean cancelledOrChangedPassword = false;
+
+ do
+ {
+ passwordInputDialog =
+ new PasswordInputDialog(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ NLS.bind(
+ CertificateManagerNLS.Passwordinput_EnterOldKeystorePasssword_Message,
+ keyStoreNode.getName()), true, null,
+ IKeyStore.KEYSTORE_PASSWORD_MIN_SIZE);
+ if (passwordInputDialog.open() == Window.OK)
+ {
+ String newPassword = passwordInputDialog.getNewPassword();
+ String oldPassword = passwordInputDialog.getOldPassword();
+
+ if ((newPassword != null) && (oldPassword != null))
+ {
+ KeyStore keyStore = null;
+ try
+ {
+ keyStore =
+ KeyStoreUtils.loadKeystore(keyStoreNode.getFile(),
+ oldPassword.toCharArray(), keyStoreNode.getType());
+
+ try
+ {
+ //rewrite keystore with new password
+ KeyStoreUtils.changeKeystorePasswd(keyStore,
+ keyStoreNode.getFile(), oldPassword.toCharArray(),
+ newPassword.toCharArray());
+
+ //deletes old password from provider
+ if (passwordProvider.isPasswordSaved())
+ {
+ passwordProvider.deleteKeyStoreSavedPassword();
+ }
+
+ if (passwordInputDialog.needToStorePassword())
+ {
+ //store new password at provider
+ passwordProvider.saveKeyStorePassword(newPassword);
+ }
+
+ //success
+ cancelledOrChangedPassword = true;
+ EclipseUtils.showInformationDialog(
+ CertificateManagerNLS.PasswordChanged_Info_Title,
+ CertificateManagerNLS.bind(
+ CertificateManagerNLS.PasswordChanged_Info_Message,
+ keyStoreNode.getFile()));
+
+ //update tooltip and image
+ KeyStoreModelEventManager.getInstance().fireEvent(node,
+ EventType.UPDATE);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //error to change password - notify on screen
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeystoreHandler_Error_ChangingKeystorePassword,
+ e.getMessage());
+ }
+ }
+ catch (Exception e1)
+ {
+ //invalid old password
+ StudioLogger.error(ChangePasswordKeystoreHandler.class,
+ e1.getMessage(), e1);
+ cancelledOrChangedPassword = false;
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.ChangePasswordKeystoreHandler_Error_WrongOldKeystorePassword,
+ CertificateManagerNLS
+ .bind(CertificateManagerNLS.ChangePasswordKeystoreHandler_InvalidOldPassword,
+ keyStoreNode.getFile()));
+ }
+ }
+ }
+ else
+ {
+ //user cancelled screen
+ cancelledOrChangedPassword = true;
+ }
+
+ }
+ while (!cancelledOrChangedPassword);
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java new file mode 100644 index 0000000..37a91d5 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeyHandler.java @@ -0,0 +1,50 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+
+import com.motorola.studio.android.common.utilities.ui.WidgetsUtil;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizard;
+
+/**
+ * Handler to execute the create key wizard.
+ */
+public class CreateKeyHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ //retrieves the first element of the selection
+ //note that this command should be enabled only when selection.count == 1.
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStore)
+ {
+ //get keystore where to create the new key
+ final IKeyStore keyStore = (IKeyStore) node;
+ CreateKeyWizard createKeyWizard = new CreateKeyWizard(keyStore);
+ WidgetsUtil.runWizard(createKeyWizard);
+ }
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java new file mode 100644 index 0000000..d56981f --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/CreateKeystoreHandler.java @@ -0,0 +1,51 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeystoreWizard;
+
+/**
+ * Handler to execute the create keystore wizard.
+ * */
+public class CreateKeystoreHandler extends AbstractHandler implements IHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+
+ CreateKeystoreWizard createKeystoreWizard = new CreateKeystoreWizard();
+
+ WizardDialog dialog = new WizardDialog(shell, createKeystoreWizard);
+
+ //open the wizard to create keystores
+ //the result doesn't need to be handled as it is self-contained
+ dialog.create();
+ dialog.open();
+
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java new file mode 100644 index 0000000..ab73f89 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeyHandler.java @@ -0,0 +1,137 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class deletes the key entry from the tree of the {@link KeystoreManagerView}
+ * */
+public class DeleteKeyHandler extends AbstractHandler2 implements IHandler
+{
+
+ /*
+ * Question dialog confirming deletion of the key with a toggle
+ * asking if the key should also be deleted from the filesystem
+ * @return true if the deletion is confirmed, false otherwise and true in the
+ * toggleState if it can also be deleted from the filesystem, false otherwise
+ */
+ private boolean showQuestion(List<ITreeNode> nodesToDelete)
+ {
+
+ final Boolean[] reply = new Boolean[1];
+
+ final String entryName = nodesToDelete.size() == 1 ? nodesToDelete.get(0).getName() : null;
+
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
+ Shell shell = ww.getShell();
+
+ reply[0] =
+ MessageDialog
+ .openQuestion(
+ shell,
+ CertificateManagerNLS.DeleteKeyHandler_ConfirmationQuestionDialog_Title,
+ entryName != null
+ ? CertificateManagerNLS
+ .bind(CertificateManagerNLS.DeleteKeyHandler_ConfirmationQuestionDialog_Description,
+ entryName)
+ : CertificateManagerNLS.DeleteKeyHandler_Delete_Selected_Keys);
+ }
+ });
+
+ return reply[0];
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ List<ITreeNode> nodesToDelete = getSelection();
+
+ if (!nodesToDelete.isEmpty())
+ {
+ boolean shouldProceed = showQuestion(nodesToDelete);
+ if (shouldProceed)
+ {
+ Map<IKeyStore, List<String>> deleteNodesMap = getKeysMap(nodesToDelete);
+
+ for (IKeyStore keyStore : deleteNodesMap.keySet())
+ {
+ try
+ {
+ keyStore.removeKeys(deleteNodesMap.get(keyStore));
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ throw new ExecutionException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ nodesToDelete.clear();
+
+ return null;
+ }
+
+ private Map<IKeyStore, List<String>> getKeysMap(List<ITreeNode> nodesToDelete)
+ {
+ Map<IKeyStore, List<String>> deleteNodesMap = new HashMap<IKeyStore, List<String>>();
+ for (ITreeNode node2Delete : nodesToDelete)
+ {
+ if (node2Delete instanceof EntryNode)
+ {
+ EntryNode entryNode = (EntryNode) node2Delete;
+ IKeyStore iKeyStore = (IKeyStore) entryNode.getParent();
+ List<String> keyList = deleteNodesMap.get(iKeyStore);
+ if (keyList == null)
+ {
+ keyList = new ArrayList<String>();
+ }
+ keyList.add(entryNode.getAlias());
+ deleteNodesMap.put(iKeyStore, keyList);
+ }
+ }
+ return deleteNodesMap;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java new file mode 100644 index 0000000..4188408 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/DeleteKeystoreHandler.java @@ -0,0 +1,120 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * This class deletes the keystore from the tree of the {@link KeystoreManagerView}
+ * */
+public class DeleteKeystoreHandler extends AbstractHandler2 implements IHandler2
+{
+
+ private static boolean toggleState = false;
+
+ /*
+ * Question dialog confirming deletion of the keystore with a toggle
+ * asking if the keystore should also be deleted from the filesystem
+ * @return true if the deletion is confirmed, false otherwise and true in the
+ * toggleState if it can also be deleted from the filesystem, false otherwise
+ */
+ private boolean showQuestion(List<ITreeNode> nodesToDelete)
+ {
+
+ final Boolean[] reply = new Boolean[2];
+
+ final String keystoreName =
+ nodesToDelete.size() == 1 ? nodesToDelete.get(0).getName() : null;
+
+ PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow ww = workbench.getActiveWorkbenchWindow();
+ Shell shell = ww.getShell();
+
+ MessageDialogWithToggle dialog =
+ MessageDialogWithToggle
+ .openYesNoQuestion(
+ shell,
+ CertificateManagerNLS.DeleteKeystoreHandler_ConfirmationQuestionDialog_Title,
+ keystoreName != null
+ ? CertificateManagerNLS
+ .bind(CertificateManagerNLS.DeleteKeystoreHandler_ConfirmationQuestionDialog_Description,
+ keystoreName)
+ : CertificateManagerNLS.DeleteKeystoreHandler_Delete_Selected_Keystores,
+ CertificateManagerNLS.DeleteKeystoreHandler_ConfirmationQuestionDialog_Toggle,
+ false, null, null);
+ reply[0] = (dialog.getReturnCode() == IDialogConstants.YES_ID);
+ reply[1] = dialog.getToggleState();
+ }
+ });
+
+ toggleState = reply[1];
+
+ return reply[0];
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ List<ITreeNode> nodesToDelete = getSelection();
+
+ if (!nodesToDelete.isEmpty())
+ {
+ boolean shouldProceed = showQuestion(nodesToDelete);
+ if (shouldProceed)
+ {
+ for (ITreeNode node2Delete : nodesToDelete)
+ {
+ KeyStoreNode keyStoreNode = (KeyStoreNode) node2Delete;
+
+ // remove from the tree
+ SigningAndKeysModelManager.getInstance().unmapKeyStore(keyStoreNode);
+
+ if (toggleState)
+ {
+ keyStoreNode.getFile().delete();
+ }
+ }
+ }
+ }
+
+ nodesToDelete.clear();
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java new file mode 100644 index 0000000..c915318 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeyStoreEntriesHandler.java @@ -0,0 +1,98 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.importks.ImportEntriesDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Handler to execute the wizard that import keys from one keystore to another.
+ * */
+public class ImportKeyStoreEntriesHandler extends AbstractHandler2
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ ITreeNode node = getSelection().get(0);
+
+ if (node instanceof IKeyStore)
+ {
+ IKeyStore keyStore = (IKeyStore) node;
+ ImportEntriesDialog dialog =
+ new ImportEntriesDialog(PlatformUI.getWorkbench().getModalDialogShellProvider()
+ .getShell(), keyStore);
+ int diagStatus = dialog.open();
+ if (diagStatus == Dialog.OK)
+ {
+ IKeyStore sourceKeyStore = dialog.getKeyStore();
+ String sourcePassword = dialog.getPassword();
+ Map<String, String> aliases = dialog.getAliases();
+ IKeyStore targetKeyStore = dialog.getTargetKeyStore();
+
+ PasswordProvider passwordProvider = targetKeyStore.getPasswordProvider();
+ String password;
+ boolean invalidPassword = false;
+ do
+ {
+ try
+ {
+ password = passwordProvider.getKeyStorePassword(true);
+ if (password != null)
+ {
+ KeyStoreUtils
+ .importKeys(targetKeyStore.getKeyStore(),
+ targetKeyStore.getFile(), targetKeyStore.getType(),
+ password.toCharArray(), sourceKeyStore.getKeyStore(),
+ sourceKeyStore.getFile(), sourcePassword.toCharArray(),
+ aliases);
+ invalidPassword = false;
+ targetKeyStore.forceReload(password.toCharArray(), true);
+ }
+ else
+ {
+ break;
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(e);
+ }
+ catch (InvalidPasswordException e)
+ {
+ invalidPassword = true;
+ }
+ }
+ while (invalidPassword);
+
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java new file mode 100644 index 0000000..6c83e66 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/ImportKeystoreHandler.java @@ -0,0 +1,52 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.wizards.ImportKeystoreWizard;
+
+/**
+ * This class maps the keystore file into the tree of the KeyStore Manager View.
+ * */
+public class ImportKeystoreHandler extends AbstractHandler implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+
+ ImportKeystoreWizard createKeystoreWizard = new ImportKeystoreWizard();
+
+ WizardDialog dialog = new WizardDialog(shell, createKeystoreWizard);
+
+ //open the wizard to import keystores
+ //the result doesn't need to be handled as it is self-contained
+ dialog.create();
+ dialog.open();
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java new file mode 100644 index 0000000..908f7ea --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RefreshHandler.java @@ -0,0 +1,39 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+
+/**
+ * Handler to execute the refresh operation.
+ * */
+public class RefreshHandler extends AbstractHandler2 implements IHandler
+{
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ KeyStoreModelEventManager.getInstance().fireEvent(getSelection().get(0), EventType.REFRESH);
+
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java new file mode 100644 index 0000000..33ada45 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/RestoreBackupHandler.java @@ -0,0 +1,306 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.command;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.dialogs.RestoreBackupDialog;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+/**
+ * Handler to execute the restore backup wizard.
+ * */
+public class RestoreBackupHandler extends AbstractHandler implements IHandler
+{
+
+ Date lastBackupDate = new Date();
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException
+ {
+ RestoreBackupDialog dialog =
+ new RestoreBackupDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+ .getShell());
+
+ int diagReturn = dialog.open();
+ if (diagReturn == Dialog.OK)
+ {
+ File archiveFile = dialog.getArchiveFile();
+ File destinationFile = dialog.getDestinationDir();
+ List<String> selectedKeyStores = dialog.getSelectedKeyStores();
+
+ restoreBackup(archiveFile, destinationFile, selectedKeyStores);
+ }
+
+ return null;
+ }
+
+ private void restoreBackup(File archiveFile, File destinationFile,
+ List<String> selectedKeyStores)
+ {
+ boolean extractionSuccess = false;
+ File typePropertiesFile = new File(destinationFile, BackupHandler.KS_TYPES_FILENAME); //$NON-NLS-1$
+ try
+ {
+ extractionSuccess =
+ FileUtil.extractZipArchive(archiveFile, destinationFile,
+ Arrays.asList(new String[]
+ {
+ BackupHandler.KS_TYPES_FILENAME
+ }), new NullProgressMonitor());
+
+ extractionSuccess =
+ FileUtil.extractZipArchive(archiveFile, destinationFile, selectedKeyStores,
+ new NullProgressMonitor());
+ }
+ catch (IOException e)
+ {
+ //roll back: delete files, if they were created
+ rollBackDeleteExtractedFiles(destinationFile, selectedKeyStores);
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Title,
+ NLS.bind(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Message,
+ archiveFile),
+ new Status(
+ IStatus.ERROR,
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Status,
+ CertificateManagerActivator.PLUGIN_ID, e));
+ }
+
+ if (extractionSuccess)
+ {
+ Properties properties = null;
+
+ if ((typePropertiesFile != null) && !typePropertiesFile.exists())
+ {
+ showWarningAboutNonIdentifiedKeystoreType(selectedKeyStores);
+ }
+ properties = loadTypeProperties(typePropertiesFile, properties);
+ //recover last backup date
+ getDateFromProperties(properties);
+
+ List<String> nonIdentifiedKeystoreTypes = new ArrayList<String>();
+
+ for (String keyStoreFileName : selectedKeyStores)
+ {
+ File keyStoreFile = new File(destinationFile, keyStoreFileName);
+ String ksType = null;
+ if (properties != null)
+ {
+ ksType = (String) properties.get(keyStoreFileName);
+ if (ksType == null)
+ {
+ //type not found at metadata
+ nonIdentifiedKeystoreTypes.add(keyStoreFileName);
+ }
+ }
+
+ if (ksType == null)
+ {
+ ksType = KeyStoreManager.getInstance().getDefaultType(); // set the keystore type to be the default type
+ }
+ KeyStoreNode keyStoreNode = new KeyStoreNode(keyStoreFile, ksType);
+ keyStoreNode.setLastBackupDate(lastBackupDate);
+
+ boolean map = true;
+ try
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (keyStore.getFile().equals(keyStoreFile))
+ {
+ //updates keystore type if necessary
+ if ((ksType != null)
+ && (ksType.compareToIgnoreCase(keyStore.getType()) != 0))
+ {
+ keyStore.setType(ksType);
+ }
+ KeyStoreModelEventManager.getInstance().fireEvent((ITreeNode) keyStore,
+ EventType.COLLAPSE);
+ map = false;
+ keyStore.setLastBackupDate(lastBackupDate);
+ }
+ }
+
+ if (map)
+ {
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keyStoreNode);
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Mapping_Title,
+ CertificateManagerNLS.RestoreBackupHandler_Error_Mapping_Message,
+ new Status(
+ IStatus.ERROR,
+ CertificateManagerNLS.RestoreBackupHandler_Error_Mapping_Status,
+ CertificateManagerActivator.PLUGIN_ID, e));
+ if (map)
+ {
+ //roll back operation - undo mapping if keystore was mapped during backup
+ SigningAndKeysModelManager.getInstance().unmapKeyStore(keyStoreNode);
+ }
+ }
+ }
+
+ if ((nonIdentifiedKeystoreTypes != null) && !nonIdentifiedKeystoreTypes.isEmpty())
+ {
+ showWarningAboutNonIdentifiedKeystoreType(nonIdentifiedKeystoreTypes);
+ }
+
+ }
+ else
+ {
+ //roll back: delete files, if they were created
+ rollBackDeleteExtractedFiles(destinationFile, selectedKeyStores);
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Title,
+ NLS.bind(
+ CertificateManagerNLS.RestoreBackupHandler_Error_Restoring_Backup_Message,
+ archiveFile));
+ }
+ }
+
+ private void rollBackDeleteExtractedFiles(File destinationFile, List<String> selectedKeyStores)
+ {
+ //roll back: delete files, if they were created
+ File ksTypeDest = new File(destinationFile, BackupHandler.KS_TYPES_FILENAME);
+ if (ksTypeDest.exists())
+ {
+ //roll back: delete Kstypes
+ ksTypeDest.delete();
+ }
+ for (String keyStoreFileName : selectedKeyStores)
+ {
+ //roll back: delete extract files
+ File keyStoreFile = new File(destinationFile, keyStoreFileName);
+ if (keyStoreFile.exists())
+ {
+ keyStoreFile.delete();
+ }
+ }
+ }
+
+ private void getDateFromProperties(Properties properties)
+ {
+ if (properties != null)
+ {
+ //KsTypes.csv available
+ String lastString = properties.getProperty("lastBackupDate");
+ Long time = new Long(lastString);
+ lastBackupDate.setTime(time);
+ }
+ else
+ {
+ //KsTypes.csv not available
+ StudioLogger.debug("KsTypes.csv not available to get lastBackupDate properties");
+ }
+ }
+
+ /**
+ * Shows warning stating that some keystores will use default keystore type.
+ * @param selectedKeyStores
+ */
+ private void showWarningAboutNonIdentifiedKeystoreType(List<String> selectedKeyStores)
+ {
+ EclipseUtils
+ .showWarningDialog(
+ CertificateManagerNLS.RestoreBackupHandler_RestoreIssue_WarningTitle,
+ CertificateManagerNLS
+ .bind(CertificateManagerNLS.RestoreBackupHandler_RestoreIssue_MissingMetadataFile_WarningDescription,
+ selectedKeyStores, KeyStore.getDefaultType()));
+ }
+
+ private Properties loadTypeProperties(File typePropertiesFile, Properties properties)
+ {
+ if ((typePropertiesFile != null) && typePropertiesFile.exists())
+ {
+ FileInputStream propInStream = null;
+ properties = new Properties();
+ try
+ {
+ propInStream = new FileInputStream(typePropertiesFile);
+ properties.load(propInStream);
+
+ typePropertiesFile.delete();
+ }
+ catch (FileNotFoundException e)
+ {
+ properties = null;
+ }
+ catch (IOException e)
+ {
+ properties = null;
+ }
+ finally
+ {
+ if (propInStream != null)
+ {
+ try
+ {
+ propInStream.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close steam while loading type properties. "
+ + e.getMessage());
+ }
+ typePropertiesFile.delete();
+ }
+ }
+
+ }
+ return properties;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java new file mode 100644 index 0000000..3551842 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/SignExternalPackagesHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.command; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler2; +import org.eclipse.jface.action.Action; + +import com.motorolamobility.studio.android.certmanager.ui.action.SignCreatedPackageAction; + +/** + * Handler to execute the sign package wizard. + * */ +public class SignExternalPackagesHandler extends AbstractHandler2 implements IHandler2 +{ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException + { + Action action = new SignCreatedPackageAction(); + action.run(); + return null; + } + +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java new file mode 100644 index 0000000..72ae028 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/command/UnsignExternalPackagesHandler.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.command; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.jface.action.Action; + +import com.motorolamobility.studio.android.certmanager.ui.action.RemoveSignatureAction; + +/** + * Handler to execute the unsign package wizard. + * */ +public class UnsignExternalPackagesHandler extends AbstractHandler implements IHandler +{ + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException + { + Action action = new RemoveSignatureAction(); + action.run(); + return null; + } + +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java new file mode 100644 index 0000000..319e46c --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/BackwardKeystoreManager.java @@ -0,0 +1,164 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.equinox.security.storage.ISecurePreferences;
+import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
+import org.eclipse.equinox.security.storage.StorageException;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+/**
+ * Manages old MOTODEV keystore available at <user_home>\motodevstudio\tools\motodev.keystore
+ * (to keep backward compatibility)
+ */
+public class BackwardKeystoreManager
+{
+ /**
+ * MOTODEV Studio directory.
+ */
+ private static final String MOTODEV_TOOLS_PATH = File.separator
+ + "motodevstudio" + File.separator + "tools"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * Path to user home directory.
+ */
+ private static final String USER_HOME_PATH = System.getProperty("user.home"); //$NON-NLS-1$
+
+ /**
+ * Full path where the files will be.
+ */
+ private static final String TOOLS_FULL_PATH = USER_HOME_PATH + MOTODEV_TOOLS_PATH;
+
+ private static final String KS_FILENAME_NEW = TOOLS_FULL_PATH + File.separatorChar
+ + "motodev.keystore"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keysotre type.
+ */
+ private static final String KS_TYPE = "JCEKS"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keystore password.
+ */
+ private static final String KS_DEFAULT_PASSWD = "passwd"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keystore password node on secure storage.
+ */
+ private static final String KS_PASSWD_NODE = "com.motorola.studio.platform.tools.sign.core"; //$NON-NLS-1$
+
+ /**
+ * The constant contains the keystore password attribute on secure storage.
+ */
+ private static final String KS_PASSWD_ATTRIBUTE = "kspasswd"; //$NON-NLS-1$
+
+ /*
+ * Removes old keystore password from Eclipse secure preferences (old format)
+ * @return the stored password (before removal),
+ * {@link SigningCoreConstants#KS_DEFAULT_PASSWD} if found node {@link SigningCoreConstants#KS_PASSWD_NODE} but {@link SigningCoreConstants#KS_PASSWD_ATTRIBUTE} does not exist,
+ * null if node {@link SigningCoreConstants#KS_PASSWD_NODE} not found
+ */
+ private String removeOldKeystorePassword()
+ {
+ String oldPassword = KS_DEFAULT_PASSWD;
+ ISecurePreferences preferences = SecurePreferencesFactory.getDefault();
+ ISecurePreferences node = null;
+ try
+ {
+ if (preferences.nodeExists(KS_PASSWD_NODE))
+ {
+ //old format node exists = try to get from attribute
+ node = preferences.node(KS_PASSWD_NODE);
+ try
+ {
+ oldPassword = node.get(KS_PASSWD_ATTRIBUTE, KS_DEFAULT_PASSWD);
+ }
+ catch (StorageException e)
+ {
+ oldPassword = KS_DEFAULT_PASSWD;
+ }
+ node.remove(KS_PASSWD_ATTRIBUTE);
+ preferences.remove(KS_PASSWD_NODE);
+ node.flush();
+ }
+ else
+ {
+ //node already removed => password is in the new format
+ oldPassword = null;
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(BackwardKeystoreManager.class, e.getMessage(), e);
+ }
+ return oldPassword;
+ }
+
+ /**
+ * Maps old keystore if the <user_home>\motodevstudio\tools\motodev.keystore file exists.
+ */
+ public void mapOldKeystore()
+ {
+ File motodevKeystoreFile = new File(KS_FILENAME_NEW);
+ if (motodevKeystoreFile.exists())
+ {
+ //we found backward (old default MOTODEV keystore) => import it
+ KeyStoreNode keyStoreNode = new KeyStoreNode(motodevKeystoreFile, KS_TYPE);
+
+ try
+ {
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keyStoreNode);
+
+ //remove old password from keystore
+ String oldPassword = removeOldKeystorePassword();
+
+ if (oldPassword != null)
+ {
+ //oldPassword was in old format => add password for keystore in the new format
+ PasswordProvider passwordProvider =
+ new PasswordProvider(keyStoreNode.getFile());
+ passwordProvider.saveKeyStorePassword(oldPassword);
+
+ //for each child key (save the same password as the keystore to maintain backward compatibility)
+ List<IKeyStoreEntry> iKeyStoreEntries = keyStoreNode.getEntries(oldPassword);
+ if (iKeyStoreEntries != null)
+ {
+ for (IKeyStoreEntry keyStoreEntry : iKeyStoreEntries)
+ {
+ passwordProvider.savePassword(keyStoreEntry.getAlias(), oldPassword);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ //error
+ EclipseUtils.showErrorDialog(CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeystoreManagerView_ErrorImportingBackwardKeystore,
+ motodevKeystoreFile), e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java new file mode 100644 index 0000000..1d8bae6 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreManager.java @@ -0,0 +1,303 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreRootNode;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Provides a common interface to manipulate keystores.
+ * Other plugins need to use it (to avoid knowing {@link KeyStoreRootNode} model and {@link SaveStateManager}).
+ *
+ * The {@link KeystoreManagerView} also need to call its methods to guarantee persistence of its operations.
+ */
+public class KeyStoreManager
+{
+ public static final String KEYSTORE_TYPE_PKCS12 = "PKCS12";
+
+ public static final String KEYSTORE_TYPE_JCEKS = "JCEKS";
+
+ public static final String KEYSTORE_TYPE_JKS = "JKS";
+
+ private static final String ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE =
+ "Error to access keystore mapping persistence";
+
+ private static KeyStoreManager _instance;
+
+ private List<IKeyStore> keyStores = null;
+
+ /**
+ * This class is a singleton.
+ * @return The unique instance of this class.
+ * */
+ public synchronized static KeyStoreManager getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new KeyStoreManager();
+ }
+ return _instance;
+ }
+
+ private KeyStoreManager()
+ {
+ }
+
+ /**
+ * Add a new keystore to the manager.
+ * @param keystore The keystore to be added.
+ * @throws KeyStoreManagerException if an error occurs while accessing persistence file where keystores are mapped.
+ */
+ public void addKeyStore(IKeyStore keystore) throws KeyStoreManagerException
+ {
+ SaveStateManager manager = null;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ manager.addEntry(keystore.getFile(), keystore.getType());
+ getKeyStores().add(keystore);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+
+ /**
+ * Remove a keystore from the manager.
+ * @param keystore The keystore to be removed.
+ * @throws KeyStoreManagerException if an error occurs while accessing persistence file where keystores are mapped.
+ */
+ public void removeKeyStore(IKeyStore keystore) throws KeyStoreManagerException
+ {
+ SaveStateManager manager = null;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ manager.removeEntry(keystore.getFile());
+ getKeyStores().remove(keystore);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+
+ /**
+ * Set the date which the keystore was added to a backup file.
+ * @param keyStore The keystore to be set.
+ * @param backupDate The date of the backup.
+ * @throws KeyStoreManagerException If there were problems while persisting the information.
+ * */
+ public void setBackupDate(IKeyStore keyStore, Date backupDate) throws KeyStoreManagerException
+ {
+ if ((keyStore != null) && (backupDate != null))
+ {
+ try
+ {
+ SaveStateManager manager = SaveStateManager.getInstance();
+ manager.setBackupDate(keyStore.getFile(), backupDate);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+ }
+
+ /**
+ * Update the type of a managed keystore, using solely the information provided by the keystore.
+ * @param keystore The keystore which type needs to be updated.
+ * @throws KeyStoreManagerException If there were problems while persisting the information.
+ * */
+ public void updateKeyStoreType(IKeyStore keyStore) throws KeyStoreManagerException
+ {
+ SaveStateManager manager;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ if (manager.isKeystoreMapped(keyStore.getFile()))
+ {
+ manager.addEntry(keyStore.getFile(), keyStore.getType());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+
+ }
+
+ /**
+ * @return The list of mapped keystores in the persistence, or empty list if there is no keystore mapped.
+ * @throws KeyStoreManagerException if an error occurs to access persistence file where keystores are mapped.
+ */
+ public List<IKeyStore> getKeyStores() throws KeyStoreManagerException
+ {
+ if (keyStores == null)
+ {
+ keyStores = new ArrayList<IKeyStore>();
+ SaveStateManager manager = null;
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ if (manager.getMappedKeystores() != null)
+ {
+ for (File keystoreFile : manager.getMappedKeystores())
+ {
+ SaveStateManager.ViewStateEntry stateEntry = manager.getEntry(keystoreFile);
+ if (stateEntry != null)
+ {
+ IKeyStore keyStoreNode = new KeyStoreNode(keystoreFile);
+ keyStoreNode.setType(stateEntry.getKeystoreType());
+ keyStoreNode.setLastBackupDate(stateEntry.getBackupDate());
+ keyStores.add(keyStoreNode);
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ throw new KeyStoreManagerException(ERROR_TO_ACCESS_KEYSTORE_MAPPING_PERSISTENCE, e);
+ }
+ }
+ return keyStores;
+ }
+
+ /**
+ * Check if a keystore file is already mapped.
+ * The input parameter is a File, instead of a String, to ensure that File.getCanonicalPath() will be used in the filenames comparison.
+ * @param keystoreFile A file representing the keystore.
+ * @return True if the file is already mapped, false otherwise.
+ * */
+ public boolean isKeystoreMapped(File keystoreFile)
+ {
+ boolean result = false;
+ SaveStateManager manager = null;
+
+ try
+ {
+ manager = SaveStateManager.getInstance();
+ if (manager.getMappedKeystores() != null)
+ {
+ for (File mappedKeystoreFile : manager.getMappedKeystores())
+ {
+ if (mappedKeystoreFile.getCanonicalPath().equals(
+ keystoreFile.getCanonicalPath()))
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ result = false;
+ StudioLogger
+ .error(getClass(),
+ "IOException while trying to check if a file is mapped on Signing and Keys view.");
+ }
+
+ return result;
+ }
+
+ /**
+ * The current available keystore types are:
+ * <ul>
+ * <li>JKS</li>
+ * <li>JCEKS</li>
+ * <li>PKCS12</li>
+ * </ul>
+ * @return The list of available keystore types.
+ * */
+ public List<String> getAvailableTypes()
+ {
+ List<String> availableKeystoreTypes = new ArrayList<String>();
+
+ availableKeystoreTypes.add(KEYSTORE_TYPE_JKS);
+ availableKeystoreTypes.add(KEYSTORE_TYPE_JCEKS);
+ availableKeystoreTypes.add(KEYSTORE_TYPE_PKCS12);
+
+ if (!availableKeystoreTypes.contains(getDefaultType()))
+ {
+ availableKeystoreTypes.add(getDefaultType());
+ }
+
+ return availableKeystoreTypes;
+ }
+
+ /**
+ * When no store type is specified, the manager define a type that should be used as the default one.
+ * @return The default keystore type used in the Signing and Keys view.
+ * */
+ public String getDefaultType()
+ {
+ return KeyStore.getDefaultType().toUpperCase();
+ }
+
+ /**
+ * Create a new keystore given a file, a store type and a password.
+ */
+ public static IKeyStore createKeyStore(File keyStoreFile, String keyStoreType, char[] password)
+ throws KeyStoreManagerException
+ {
+ IKeyStore keyStoreNode = null;
+ try
+ {
+ KeyStore keyStore = KeyStoreUtils.createKeystore(keyStoreFile, keyStoreType, password);
+ keyStoreNode = new KeyStoreNode(keyStoreFile, keyStore);
+ }
+ catch (InvalidPasswordException e)
+ {
+ StudioLogger.error("Invalid password when creating a keystore: " + e.getMessage());
+ }
+ return keyStoreNode;
+ }
+
+ /**
+ * Create a new keystore given a file and a password.
+ * The store type is set to be the default.
+ */
+ public static IKeyStore createKeyStore(File keyStoreFile, char[] password)
+ throws KeyStoreManagerException
+ {
+ IKeyStore keyStoreNode = null;
+ try
+ {
+ KeyStore keyStore = KeyStoreUtils.createKeystore(keyStoreFile, password);
+ keyStoreNode = new KeyStoreNode(keyStoreFile, keyStore);
+ }
+ catch (InvalidPasswordException e)
+ {
+ StudioLogger.error("Invalid password when creating a keystore: " + e.getMessage());
+ }
+
+ return keyStoreNode;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java new file mode 100644 index 0000000..46f6fc5 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtils.java @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.core; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStore.Builder; +import java.security.KeyStore.Entry; +import java.security.KeyStore.PasswordProtection; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStore.ProtectionParameter; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Map; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStrictStyle; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.bc.BcContentSignerBuilder; +import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; +import org.eclipse.osgi.util.NLS; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorola.studio.android.common.utilities.FileUtil; +import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; +import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo; + +public class KeyStoreUtils +{ + private static final String ERROR_DELETING_ALIAS = + CertificateManagerNLS.KeyStoreUtils_ErrorDeletingAlias; + + /** + * Creates a new empty KeyStore, from the default type, located at keyStoreFile with the password, password + * @param keyStoreFile The file pointing o where the new KeyStore will be located + * @param password the password for the new KeyStore + * @return the {@link KeyStore} representing the new KeyStore + * @throws InvalidPasswordException + * @throws KeyStoreException if KeyStore can't be created + */ + public static KeyStore createKeystore(File keyStoreFile, char[] password) + throws KeyStoreManagerException, InvalidPasswordException + { + return createKeystore(keyStoreFile, KeyStore.getDefaultType(), password); + } + + /** + * Creates a new empty KeyStore, located at keyStoreFile with the password, password + * @param keyStoreFile The file pointing o where the new KeyStore will be located + * @param keyStoreType The type of the new KeyStore + * @param password the password for the new KeyStore + * @return the {@link KeyStore} representing the new KeyStore + * @throws InvalidPasswordException + * @throws KeyStoreException if KeyStore can't be created + */ + public static KeyStore createKeystore(File keyStoreFile, String keyStoreType, char[] password) + throws KeyStoreManagerException, InvalidPasswordException + { + KeyStore keyStore = null; + if ((keyStoreFile != null) && !keyStoreFile.exists()) + { + keyStore = loadKeystore(keyStoreFile, password, keyStoreType); + try + { + writeKeyStore(keyStore, password, keyStoreFile); + } + catch (Exception e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_WriteKeyStore, keyStoreFile), e); + } + } + else + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_FileAlreadyExists, keyStoreFile)); + } + + return keyStore; + } + + public static void writeKeyStore(KeyStore keyStore, char[] password, File keyStoreFile) + throws FileNotFoundException, KeyStoreException, IOException, NoSuchAlgorithmException, + CertificateException, KeyStoreManagerException, InvalidPasswordException + { + + writeKeyStore(keyStore, null, password, keyStoreFile); + } + + private static void writeKeyStore(KeyStore keyStore, char[] oldPassword, char[] newPassword, + File keyStoreFile) throws FileNotFoundException, KeyStoreException, IOException, + NoSuchAlgorithmException, CertificateException, KeyStoreManagerException, + InvalidPasswordException + { + FileOutputStream fos = null; + try + { + if (oldPassword != null) + { + if (loadKeystore(keyStoreFile, oldPassword, keyStore.getType()) != null) + { + fos = new FileOutputStream(keyStoreFile); + keyStore.store(fos, newPassword); + } + } + else + { + fos = new FileOutputStream(keyStoreFile); + keyStore.store(fos, newPassword); + } + } + finally + { + if (fos != null) + { + try + { + fos.close(); + } + catch (IOException e) + { + StudioLogger.error("Could not close steam while writing keystore file. " + + e.getMessage()); + } + } + } + } + + /** + * Loads a KeyStore from a given file from the default type, usually JKS. + * If keyStoreFile path don't exist then a new empty KeyStore will be created on the given location. + * <b>Note:</b> Calling this method is the same as calling loadKeystore(keyStoreFile, password, KeyStore.getDefaultType()) + * @param keyStoreFile The keyStore location. + * @param password The KeyStore password + * @return the {@link KeyStore} representing the file. + * @throws KeyStoreManagerException + * @throws InvalidPasswordException + */ + public static KeyStore loadKeystore(File keyStoreFile, char[] password) + throws KeyStoreManagerException, InvalidPasswordException + { + return loadKeystore(keyStoreFile, password, KeyStore.getDefaultType()); + } + + /** + * Loads a KeyStore from a given file. + * If keyStoreFile path don't exist then a new empty KeyStore will be created on memory. + * If you want o create a new KeyStore file, calling createStore is recommended. + * @param keyStoreFile The keyStore location. + * @param password The KeyStore password + * @param storeType The Type of the keystore o be loaded. + * @return the {@link KeyStore} representing the file. + * @throws KeyStoreManagerException + * @throws InvalidPasswordException + */ + public static KeyStore loadKeystore(File keyStoreFile, char[] password, String storeType) + throws KeyStoreManagerException, InvalidPasswordException + { + KeyStore keyStore = null; + FileInputStream fis = null; + try + { + keyStore = KeyStore.getInstance(storeType); + + if ((keyStoreFile != null) && keyStoreFile.exists() && (keyStoreFile.length() > 0)) + { + fis = new FileInputStream(keyStoreFile); + } + + //fis = null means a new keyStore will be created + keyStore.load(fis, password); + } + catch (IOException e) + { + if (e.getMessage().contains("password was incorrect") + || (e.getCause() instanceof UnrecoverableKeyException)) + { + throw new InvalidPasswordException(e.getMessage()); + } + else + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_LoadKeyStore, keyStoreFile), e); + } + } + catch (Exception e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_LoadKeyStore, keyStoreFile), e); + } + finally + { + if (fis != null) + { + try + { + fis.close(); + } + catch (IOException e) + { + StudioLogger.error("Could not close steam while loading keystore. " + + e.getMessage()); + } + } + } + + return keyStore; + } + + /** + * Simply deletes the KeyStore File + * @param keyStoreFile teh KeyStore file to be deleted. + * @throws KeyStoreException If any error occur. + */ + public static void deleteKeystore(File keyStoreFile) throws KeyStoreManagerException + { + try + { + FileUtil.deleteFile(keyStoreFile); + } + catch (IOException e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_DeleteKeyStore, keyStoreFile), e); + } + } + + /** + * Write the keyStore in to the given file, protecting it with password. + * Warn: Since there's actually no way to change the password this method will overwrite the existing file with the keyStore contents, + * without further warning. + * @param keyStore the {@link KeyStore} to be written. + * @param keyStoreFile The KeyStore location + * @param oldPassword + * @param sourcePassword the new Password + * @throws KeyStoreException If file could no be write. + */ + public static void changeKeystorePasswd(KeyStore keyStore, File keyStoreFile, + char[] oldPassword, char[] newPassword) throws KeyStoreManagerException + { + try + { + keyStore = loadKeystore(keyStoreFile, oldPassword, keyStore.getType()); + writeKeyStore(keyStore, oldPassword, newPassword, keyStoreFile); + } + catch (Exception e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_WriteKeyStore, keyStoreFile), e); + } + } + + /** + * Adds a new enty to a given keyStore. + * @param keyStore The Keystore that will receive the entry + * @param keyStorePassword The KeyStore password + * @param keyStoreFile The KeyStore file path + * @param alias The new entry alias + * @param entry The Entry to be added + * @param entryPassword The password to protect the entry + * @throws KeyStoreManagerException if any error occurs. + */ + public static void addEntry(KeyStore keyStore, char[] keyStorePassword, File keyStoreFile, + String alias, Entry entry, char[] entryPassword) throws KeyStoreManagerException + { + try + { + PasswordProtection passwordProtection = new KeyStore.PasswordProtection(entryPassword); + keyStore = loadKeystore(keyStoreFile, keyStorePassword, keyStore.getType()); + + if (!keyStore.containsAlias(alias)) + { + keyStore.setEntry(alias, entry, passwordProtection); + writeKeyStore(keyStore, keyStorePassword, keyStoreFile); + } + else + { + throw new KeyStoreManagerException(NLS.bind("Alias \"{0}\" already exists.", alias)); + } + + } + catch (KeyStoreManagerException e) + { + throw e; + } + catch (Exception e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.KeyStoreUtils_Error_AddEntryToKeyStore, alias), e); + } + } + + /** + * Adds a new enty to a given keyStore. + * @param keyStore The Keystore that will receive the entry + * @param keyStorePassword The KeyStore password + * @param keyStoreFile The KeyStore file path + * @param alias The new entry alias + * @param entry The Entry to be added + * @param entryPassword The password to protect the entry + * @throws KeyStoreManagerException if any error occurs. + */ + public static void changeEntryPassword(KeyStore keyStore, char[] keyStorePassword, + File keyStoreFile, String alias, Entry entry, char[] entryPassword) + throws KeyStoreManagerException + { + try + { + PasswordProtection passwordProtection = new KeyStore.PasswordProtection(entryPassword); + keyStore.setEntry(alias, entry, passwordProtection); + writeKeyStore(keyStore, keyStorePassword, keyStoreFile); + } + catch (Exception e) + { + throw new KeyStoreManagerException(NLS.bind( + "Error attempting to change password for {0}", alias), e); + } + } + + /** + * Create a new X509 certificate for a given KeyPair + * @param keyPair the {@link KeyPair} used to create the certificate, + * RSAPublicKey and RSAPrivateKey are mandatory on keyPair, IllegalArgumentExeption will be thrown otherwise. + * @param issuerName The issuer name to be used on the certificate + * @param ownerName The owner name to be used on the certificate + * @param expireDate The expire date + * @return The {@link X509Certificate} + * @throws IOException + * @throws OperatorCreationException + * @throws CertificateException + */ + public static X509Certificate createX509Certificate(KeyPair keyPair, + CertificateDetailsInfo certDetails) throws IOException, OperatorCreationException, + CertificateException + { + + PublicKey publicKey = keyPair.getPublic(); + PrivateKey privateKey = keyPair.getPrivate(); + if (!(publicKey instanceof RSAPublicKey) || !(privateKey instanceof RSAPrivateKey)) + { + throw new IllegalArgumentException( + CertificateManagerNLS.KeyStoreUtils_RSA_Keys_Expected); + } + + RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey; + + //Transform the PublicKey into the BouncyCastle expected format + ASN1InputStream asn1InputStream = null; + X509Certificate x509Certificate = null; + + try + { + asn1InputStream = + new ASN1InputStream(new ByteArrayInputStream(rsaPublicKey.getEncoded())); + SubjectPublicKeyInfo pubKey = + new SubjectPublicKeyInfo((ASN1Sequence) asn1InputStream.readObject()); + + X500NameBuilder nameBuilder = new X500NameBuilder(new BCStrictStyle()); + addField(BCStyle.C, certDetails.getCountry(), nameBuilder); + addField(BCStyle.ST, certDetails.getState(), nameBuilder); + addField(BCStyle.L, certDetails.getLocality(), nameBuilder); + addField(BCStyle.O, certDetails.getOrganization(), nameBuilder); + addField(BCStyle.OU, certDetails.getOrganizationUnit(), nameBuilder); + addField(BCStyle.CN, certDetails.getCommonName(), nameBuilder); + + X500Name subjectName = nameBuilder.build(); + X500Name issuerName = subjectName; + X509v3CertificateBuilder certBuilder = + new X509v3CertificateBuilder(issuerName, BigInteger.valueOf(new SecureRandom() + .nextInt()), GregorianCalendar.getInstance().getTime(), + certDetails.getExpirationDate(), subjectName, pubKey); + + AlgorithmIdentifier sigAlgId = + new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA"); //$NON-NLS-1$ + AlgorithmIdentifier digAlgId = + new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId); + BcContentSignerBuilder sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId); + + //Create RSAKeyParameters, the private key format expected by Bouncy Castle + RSAKeyParameters keyParams = + new RSAKeyParameters(true, rsaPrivateKey.getPrivateExponent(), + rsaPrivateKey.getModulus()); + + ContentSigner contentSigner = sigGen.build(keyParams); + X509CertificateHolder certificateHolder = certBuilder.build(contentSigner); + + //Convert the X509Certificate from BouncyCastle format to the java.security format + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); + x509Certificate = certConverter.getCertificate(certificateHolder); + } + finally + { + if (asn1InputStream != null) + { + try + { + asn1InputStream.close(); + } + catch (IOException e) + { + StudioLogger.error("Could not close stream while creating X509 certificate. " + + e.getMessage()); + } + } + } + + return x509Certificate; + } + + private static void addField(ASN1ObjectIdentifier objectId, String value, + X500NameBuilder nameBuilder) + { + if (value.length() > 0) + { + nameBuilder.addRDN(objectId, value); + } + } + + /** + * Creates a new RSA KeyPair + * @return the new {@link KeyPair} + */ + public static KeyPair genKeyPair() throws NoSuchAlgorithmException + { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); //$NON-NLS-1$ + keyPairGen.initialize(2048); //As recommended by Android guys, key is created with 2048 bits. + KeyPair keyPair = keyPairGen.genKeyPair(); + return keyPair; + } + + /** + * Create a new private key entry inside the key pair + * @param keyPair + * @param x509Certificate + * @return + */ + public static PrivateKeyEntry createPrivateKeyEntry(KeyPair keyPair, + X509Certificate x509Certificate) + { + Certificate[] certChain = new Certificate[] + { + x509Certificate + }; + PrivateKeyEntry privateKeyEntry = + new KeyStore.PrivateKeyEntry(keyPair.getPrivate(), certChain); + return privateKeyEntry; + } + + public static void deleteEntry(KeyStore keyStore, char[] password, File keyStoreFile, + String alias) throws KeyStoreManagerException + { + try + { + keyStore = loadKeystore(keyStoreFile, password, keyStore.getType()); + + keyStore.deleteEntry(alias); + writeKeyStore(keyStore, password, keyStoreFile); + } + catch (Exception e) + { + StudioLogger.error(KeyStoreUtils.class, ERROR_DELETING_ALIAS + alias, e); + throw new KeyStoreManagerException(ERROR_DELETING_ALIAS + alias, e); + } + } + + /** + * Change a keyStore type. + * @param keyStoreFile The KeyStoreFile + * @param password The KeyStore Password + * @param originalType the original Type + * @param destinationType the new KeyStore Type + * @throws KeyStoreManagerException If any error occurs, the operation will be canceled and reverted automatically. + * @throws InvalidPasswordException + */ + public static void changeKeyStoreType(File keyStoreFile, char[] password, String originalType, + String destinationType, Map<String, String> aliases) throws KeyStoreManagerException, + InvalidPasswordException + { + boolean rollBack = false; + String timeStamp = Long.toString(Calendar.getInstance().getTimeInMillis()); + File oldKsFile = new File(keyStoreFile.getAbsolutePath() + "_" + timeStamp); + oldKsFile.delete(); + boolean renamed = false; + renamed = keyStoreFile.renameTo(oldKsFile); + if (renamed) + { + try + { + Builder oldKsBuilder = + KeyStore.Builder.newInstance(originalType, null, oldKsFile, + new PasswordProtection(password)); + KeyStore oldKeyStore = oldKsBuilder.getKeyStore(); + + KeyStore newKeyStore = createKeystore(keyStoreFile, destinationType, password); + for (String alias : aliases.keySet()) + { + ProtectionParameter protectionParameter = + new PasswordProtection(aliases.get(alias).toCharArray()); + Entry entry = oldKeyStore.getEntry(alias, protectionParameter); + newKeyStore.setEntry(alias, entry, protectionParameter); + } + writeKeyStore(newKeyStore, password, keyStoreFile); + } + catch (InvalidPasswordException e) + { + rollBack = true; + StudioLogger + .error(KeyStoreUtils.class, + "Invalid password while trying to create a new keystore, changing a keyStore type.", + e); + + } + catch (Exception e) + { + if (e.getMessage().contains("password was incorrect") + || e.getCause().getMessage().contains("password was incorrect")) + { + keyStoreFile.delete(); + oldKsFile.renameTo(keyStoreFile); + throw new InvalidPasswordException(e.getMessage()); + } + else + { + StudioLogger.error(KeyStoreUtils.class, + "Exception occurred while attempting to change a keyStore type.", e); + rollBack = true; + } + } + + if (rollBack) + { + keyStoreFile.delete(); + oldKsFile.renameTo(keyStoreFile); + + throw new KeyStoreManagerException(NLS.bind( + "Could not convert the KeyStore {0} to type {1}", keyStoreFile, + destinationType)); + } + } + else + { + throw new KeyStoreManagerException( + NLS.bind( + "Could not convert the KeyStore {0} to type {1}, could not backup the current keyStore file, maybe it's in use by another program.", + keyStoreFile, destinationType)); + } + oldKsFile.delete(); + } + + /** + * Import a set of entries from sourcekeystore into the targetkeystore. + * If alias already exists on the target keystore then the alias is concatenated with the + * source keystore file name. + * @param targetKeyStore + * @param targetFile + * @param targetType + * @param targetPasswd + * @param sourceKeyStore + * @param sourceKeyStoreFile + * @param sourcePasswd + * @param aliases a map<String, String> containing alias as key and its password as value. this method assume that the password is correct + * @throws InvalidPasswordException + * @throws KeyStoreManagerException + */ + public static void importKeys(KeyStore targetKeyStore, File targetFile, String targetType, + char[] targetPasswd, KeyStore sourceKeyStore, File sourceKeyStoreFile, + char[] sourcePasswd, Map<String, String> aliases) throws InvalidPasswordException, + KeyStoreManagerException + { + if (!isValidKeyStorePasswd(targetFile, targetType, targetPasswd)) + { + throw new InvalidPasswordException( + CertificateManagerNLS.PasswordChanged_InvalidKeystorePassword); + } + + try + { + for (String alias : aliases.keySet()) + { + if (sourceKeyStore.containsAlias(alias)) + { + ProtectionParameter protectionParameter = + new PasswordProtection(aliases.get(alias).toCharArray()); + Entry entry = sourceKeyStore.getEntry(alias, protectionParameter); + if (targetKeyStore.containsAlias(alias)) + { + alias += "_" + sourceKeyStoreFile.getName(); + } + int i = 1; + while (targetKeyStore.containsAlias(alias)) + { + alias += "_" + i; + i++; + } + targetKeyStore.setEntry(alias, entry, protectionParameter); + } + else + { + StudioLogger + .error(KeyStoreUtils.class, + NLS.bind( + "Alias {0} could not be imported because it doesn't exists on originKeyStore", + alias)); + } + } + writeKeyStore(targetKeyStore, targetPasswd, targetFile); + } + catch (Exception e) + { + throw new KeyStoreManagerException("Could not import the selected aliases into " + + targetFile.getName(), e); + } + } + + /** + * Verifies if the password if valid + * @param keyStoreFile + * @param keyStoreType + * @param passwd + * @return true if password is valid, false otherwise. + * @throws KeyStoreManagerException + */ + public static boolean isValidKeyStorePasswd(File keyStoreFile, String keyStoreType, + char[] passwd) throws KeyStoreManagerException + { + KeyStore keystore = null; + try + { + keystore = loadKeystore(keyStoreFile, passwd, keyStoreType); + } + catch (InvalidPasswordException e) + { + //Do nothing, password is invalid + } + return keystore != null; + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java new file mode 100644 index 0000000..9ec1abf --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/KeyStoreUtilsTest.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.core; + +import java.io.File; +import java.io.IOException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import org.bouncycastle.operator.OperatorCreationException; +import org.junit.Test; + +import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo; + +public class KeyStoreUtilsTest extends TestCase +{ + + File keyStoreFile = null; + + private String passwd; + + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception + { + keyStoreFile = File.createTempFile("testKeystore", ".tmp"); + passwd = "passwd"; + super.setUp(); + } + + @Test + public void testCreateKeystore() + { + + KeyStore keyStore = null; + try + { + keyStore = KeyStoreUtils.createKeystore(keyStoreFile, passwd.toCharArray()); + } + catch (KeyStoreManagerException e) + { + assert (false); + } + catch (InvalidPasswordException e) + { + assert (false); + } + + assert (keyStore != null); + assert (keyStoreFile.length() > 0); + + } + + @Test + public void testLoadKeyStore() + { + try + { + KeyStore keyStore = + KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS"); + keyStore.aliases(); + } + catch (KeyStoreException e) + { + assert false; + } + catch (KeyStoreManagerException e) + { + assert false; + } + catch (InvalidPasswordException e) + { + assert false; + } + } + + @Test + public void testCreateCertificate() + { + try + { + KeyStore keyStore = + KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS"); + + KeyPair keyPair = KeyStoreUtils.genKeyPair(); + X509Certificate x509Certificate = + KeyStoreUtils.createX509Certificate(keyPair, new CertificateDetailsInfo("test", + "nome", "org", "orgUn", "testUni", "country", "Estate", "30", "")); + + PrivateKeyEntry privateKeyEntry = + KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate); + + KeyStoreUtils.addEntry(keyStore, passwd.toCharArray(), keyStoreFile, "aliasTest", + privateKeyEntry, "aliaspass".toCharArray()); + } + catch (Exception e) + { + assert (false); + } + } + + @Test + public void testChangePasswd() + { + + KeyStore keyStore = null; + try + { + keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray()); + } + catch (KeyStoreManagerException e) + { + assert false; + } + catch (InvalidPasswordException e) + { + assert false; + } + + File keyStoreFile2 = new File(keyStoreFile + "_2"); + try + { + KeyStoreUtils.changeKeystorePasswd(keyStore, keyStoreFile2, passwd.toCharArray(), + "newPasswd2".toCharArray()); + } + catch (KeyStoreManagerException e) + { + assert (false); + } + + assert (keyStore != null); + assert (keyStoreFile2.length() > 0); + } + + @Test + public void testChangeKsType() + { + try + { + KeyStoreUtils.createKeystore(keyStoreFile, "JKS", passwd.toCharArray()); + KeyStoreUtils.changeKeyStoreType(keyStoreFile, passwd.toCharArray(), "JKS", "JCEKS", + new HashMap<String, String>(0)); + } + catch (KeyStoreManagerException e) + { + e.printStackTrace(); + } + catch (InvalidPasswordException e) + { + e.printStackTrace(); + } + } + + @Test + public void testImportKeys() + { + File keyStoreFile1 = new File(keyStoreFile.getAbsolutePath() + "_import"); + try + { + KeyStoreUtils.createKeystore(keyStoreFile1, "pass1".toCharArray()); + } + catch (KeyStoreManagerException e) + { + e.printStackTrace(); + } + catch (InvalidPasswordException e) + { + e.printStackTrace(); + } + try + { + KeyStore keyStore = + KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS"); + KeyPair keyPair = KeyStoreUtils.genKeyPair(); + X509Certificate x509Certificate = + KeyStoreUtils.createX509Certificate(keyPair, new CertificateDetailsInfo("test", + "nome", "org", "orgUn", "testUni", "country", "Estate", "30", "")); + + PrivateKeyEntry privateKeyEntry = + KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate); + + KeyStoreUtils.addEntry(keyStore, passwd.toCharArray(), keyStoreFile, "aliasTest", + privateKeyEntry, passwd.toCharArray()); + + keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, passwd.toCharArray(), "JKS"); + + Map<String, String> aliases = new HashMap<String, String>(1); + aliases.put("aliasTest", passwd); + // KeyStoreUtils.importKeys(keyStore1, keyStoreFile1, "pass1".toCharArray(), keyStore, keyStoreFile1 + // passwd.toCharArray(), aliases); + } + catch (KeyStoreManagerException e) + { + e.printStackTrace(); + } + catch (InvalidPasswordException e) + { + e.printStackTrace(); + } + catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + } + catch (OperatorCreationException e) + { + e.printStackTrace(); + } + catch (CertificateException e) + { + e.printStackTrace(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java new file mode 100644 index 0000000..ce73f09 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/PasswordProvider.java @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.core; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.eclipse.equinox.security.storage.ISecurePreferences; +import org.eclipse.equinox.security.storage.SecurePreferencesFactory; +import org.eclipse.equinox.security.storage.StorageException; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorola.studio.android.common.utilities.EclipseUtils; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; + +/** + * This class is responsible to retrieve passwords for a keystore and its entries. + * Usage: + * Instantiate with a keyStoreFile, call the methods getPassword. + * If needed a dialog will be shown, asking user to type the password. + */ +public class PasswordProvider +{ + + private static final String PREF_ROOT_NODE = CertificateManagerActivator.PLUGIN_ID + + "_passwords"; //$NON-NLS-1$ + + private static final String KS_PASSWORD_KEY = "KS_PASSWORD"; //$NON-NLS-1$ + + private final class KeyStorePasswdDialog extends Dialog + { + private final File keyStoreFile; + + private String passwd; + + private boolean savePasswd; + + private Text paswordText; + + private Button saveCheckBox; + + private final String alias; + + private KeyStorePasswdDialog(Shell parentShell, File keyStoreFile, String alias) + { + super(parentShell); + this.keyStoreFile = keyStoreFile; + this.alias = alias; + } + + @Override + protected Control createDialogArea(Composite parent) + { + + Composite mainComposite = new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(2, false); + mainComposite.setLayout(gridLayout); + + //Creates the message + Label messageLabel = new Label(mainComposite, SWT.NONE); + GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 2); + messageLabel.setLayoutData(gridData); + + if (this.alias.equals(KS_PASSWORD_KEY)) + { + getShell().setText(CertificateManagerNLS.PasswordProvider_DialogTitle); + messageLabel.setText(NLS.bind(CertificateManagerNLS.PasswordProvider_MessageLabel, + keyStoreFile.getName())); + } + else + { + getShell().setText(CertificateManagerNLS.CertificateBlock_KeyPassword_Label); + messageLabel.setText(NLS.bind( + CertificateManagerNLS.PasswordProvider_Key_MessageLabel, alias)); + } + + //Creates the text field label + Label passwdLabel = new Label(mainComposite, SWT.NONE); + gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false); + passwdLabel.setLayoutData(gridData); + passwdLabel.setText(CertificateManagerNLS.PasswordProvider_PasswordLabel); + + //Creates the password text + paswordText = new Text(mainComposite, SWT.BORDER | SWT.PASSWORD); + gridData = new GridData(SWT.FILL, SWT.CENTER, true, false); + paswordText.setLayoutData(gridData); + + //Creates the save password checkbox + saveCheckBox = new Button(mainComposite, SWT.CHECK); + saveCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword); + saveCheckBox.setSelection(false); + gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1); + saveCheckBox.setLayoutData(gridData); + saveCheckBox.setVisible(KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile)); + + return super.createDialogArea(parent); + } + + @Override + protected void okPressed() + { + passwd = paswordText.getText(); + savePasswd = saveCheckBox.getSelection(); + super.okPressed(); + } + + public String getPasswd() + { + return passwd; + } + + public boolean mustSavePasswd() + { + return savePasswd; + } + } + + private final File keyStoreFile; + + private final ISecurePreferences securePreferences; + + private boolean canSavePassword = true; + + public PasswordProvider(File keyStoreFile) + { + this(keyStoreFile, KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile)); + } + + public PasswordProvider(File keyStoreFile, boolean canSavePassword) + { + this.keyStoreFile = keyStoreFile; + this.securePreferences = SecurePreferencesFactory.getDefault(); + this.canSavePassword = canSavePassword; + } + + /** + * Retrieves the KeyStore password. + * @param promptPassword whether the password entry dialog will be shown or not + * @param useSavedPassword whether to use the keyStore saved password + * @return the password string or null if user canceled the dialog + * @throws KeyStoreManagerException + */ + public String getKeyStorePassword(boolean promptPassword, boolean useSavedPassword) + throws KeyStoreManagerException + { + return getPassword(KS_PASSWORD_KEY, promptPassword, useSavedPassword); + } + + /** + * Retrieves the KeyStore password. + * This method will always attempt to retrieve the saved password. + * It's behavior is the same as of calling the method getPassword(promptPassword, true) + * @param promptPassword whether the password entry dialog will be shown or not + * @return the password string or null if user canceled the dialog + * @throws KeyStoreManagerException + */ + public String getKeyStorePassword(boolean promptPassword) throws KeyStoreManagerException + { + return getPassword(KS_PASSWORD_KEY, promptPassword, true); + } + + /** + * Retrieves the password for a given alias within a keyStore. + * This method will always attempt to retrieve the saved password. + * It's behavior is the same as of calling the method getPassword(promptPassword, true) + * @param promptPassword whether the password entry dialog will be shown or not + * @return the password string or null if user canceled the dialog + * @throws KeyStoreManagerException + */ + public String getPassword(String alias, boolean promptPassword) throws KeyStoreManagerException + { + return getPassword(alias, promptPassword, true); + } + + /** + * Retrieves the password for a given alias within a keyStore. + * This method will always attempt to retrieve the saved password. + * It's behavior is the same as of calling the method getPassword(promptPassword, true) + * @param promptPassword whether the password entry dialog will be shown or not + * @param useSavedPassword whether to use the keyStore saved password + * @return the password string or null if user canceled the dialog + * @throws KeyStoreManagerException + */ + public String getPassword(String alias, boolean promptPassword, boolean useSavedPassword) + throws KeyStoreManagerException + { + String password = null; + + if (useSavedPassword) + { + if (securePreferences != null) + { + String prefKey = alias; + password = getSavedPasswd(prefKey); + } + else + { + throw new KeyStoreManagerException( + CertificateManagerNLS.PasswordProvider_Error_WhileSaving); + } + } + + if ((password == null) && promptPassword) + { + password = promptPassword(alias); + } + + return password; + } + + private String getSavedPasswd(String prefKey) + { + String password = null; + // Try to get the password from secure storage + if (securePreferences.nodeExists(PREF_ROOT_NODE)) + { + ISecurePreferences node = securePreferences.node(PREF_ROOT_NODE); + try + { + if (node.nodeExists(keyStoreFile.getAbsolutePath())) + { + ISecurePreferences ksNode = node.node(keyStoreFile.getAbsolutePath()); + password = ksNode.get(prefKey, null); + } + } + catch (StorageException e) + { + //Do nothing, password will be null. + } + } + return password; + } + + private String promptPassword(final String alias) throws KeyStoreManagerException + { + final String[] result = new String[1]; + final Boolean[] canProceed = new Boolean[1]; + + Display.getDefault().syncExec(new Runnable() + { + @Override + public void run() + { + KeyStorePasswdDialog dialog = + new KeyStorePasswdDialog(PlatformUI.getWorkbench() + .getModalDialogShellProvider().getShell(), keyStoreFile, alias); + + int diagStatus = dialog.open(); + + if (diagStatus == Dialog.OK) + { + //Read the values from the dialog and do the actions, return passwd and save if required + result[0] = dialog.getPasswd(); + + canSavePassword = KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile); + canProceed[0] = dialog.mustSavePasswd(); + } + else + { + //dialog cancelled + canProceed[0] = false; + result[0] = null; + } + } + }); + + if (canProceed[0] && canSavePassword) + { + if (securePreferences != null) + { + savePassword(alias, result[0]); + } + else + { + EclipseUtils.showWarningDialog(CertificateManagerNLS.PasswordProvider_DialogTitle, + CertificateManagerNLS.PasswordProvider_Error_WhileSaving); + } + } + + return result[0]; + } + + public void saveKeyStorePassword(String password) throws KeyStoreManagerException + { + savePassword(KS_PASSWORD_KEY, password); + } + + public void savePassword(final String alias, String password) throws KeyStoreManagerException + { + String prefKey; + canSavePassword = KeyStoreManager.getInstance().isKeystoreMapped(keyStoreFile); + if (canSavePassword) //protect from saving + { + if (alias != null) + { + prefKey = alias; + } + else + { + prefKey = KS_PASSWORD_KEY; + } + + ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE); + try + { + ISecurePreferences ksNode = rootNode.node(keyStoreFile.getAbsolutePath()); + ksNode.put(prefKey, password, true); + ksNode.flush(); + } + catch (Exception e) + { + throw new KeyStoreManagerException( + CertificateManagerNLS.PasswordProvider_Error_WhileSaving); + } + } + } + + /** + * Deletes the entire node (including KS_PASSWORD_KEY and children aliases) + * @throws KeyStoreManagerException + */ + public void deleteKeyStoreSavedPasswordNode() throws KeyStoreManagerException + { + deleteSavedPassword(null); + } + + /** + * Deletes only KS_PASSWORD_KEY (not children aliases) + */ + public void deleteKeyStoreSavedPassword() throws KeyStoreManagerException + { + deleteSavedPassword(KS_PASSWORD_KEY); + } + + public void deleteSavedPassword(String alias) throws KeyStoreManagerException + { + + ISecurePreferences ksNode = getKeyStoreNode(); + if (ksNode != null) + { + if (alias == null) + { + ksNode.removeNode(); + } + else + { + ksNode.remove(alias); + //if no item has no child, then we can remove the node + if (ksNode.keys().length == 0) + { + ksNode.removeNode(); + } + } + + try + { + ksNode.flush(); + } + catch (IllegalStateException e) + { + //Do nothing, node has already been removed + } + catch (IOException e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.PasswordProvider_Error_WhileRemovingPassword, + keyStoreFile.getName())); + } + } + } + + /** + * This method will remove all saved entries for this keystore file that is not listed on the aliasList. + * The idea is to remove all saved passwords that makes reference to non-existant entries. + * @param aliasList the list of alias to be kept if available on the security keystore + * @throws KeyStoreManagerException if writing the security keystore fails for some reason + */ + public void cleanModel(List<String> aliasList) throws KeyStoreManagerException + { + ISecurePreferences keyStoreNode = getKeyStoreNode(); + if (keyStoreNode != null) + { + String[] savedKeys = keyStoreNode.keys(); + for (String savedAlias : savedKeys) + { + if (!savedAlias.equals(KS_PASSWORD_KEY) && !aliasList.contains(savedAlias)) + { + keyStoreNode.remove(savedAlias); + } + } + try + { + keyStoreNode.flush(); + } + catch (IOException e) + { + throw new KeyStoreManagerException(NLS.bind( + CertificateManagerNLS.PasswordProvider_Error_WhileRemovingPassword, + keyStoreFile.getName())); + } + } + } + + /* + * @return the keystore node if it exists + */ + private ISecurePreferences getKeyStoreNode() + { + ISecurePreferences ksNode = null; + if (securePreferences.nodeExists(PREF_ROOT_NODE)) + { + ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE); + + if (rootNode.nodeExists(keyStoreFile.getAbsolutePath())) + { + ksNode = rootNode.node(keyStoreFile.getAbsolutePath()); + } + } + return ksNode; + } + + /** + * If keystore password is saved. + */ + public boolean isPasswordSaved() + { + return isPasswordSaved(KS_PASSWORD_KEY); + } + + /** + * If alias password is saved. + */ + public boolean isPasswordSaved(String prefKey) + { + ISecurePreferences ksNode = null; + boolean isSaved = false; + if (securePreferences.nodeExists(PREF_ROOT_NODE)) + { + ISecurePreferences rootNode = securePreferences.node(PREF_ROOT_NODE); + ksNode = rootNode.node(keyStoreFile.getAbsolutePath()); + try + { + String value = ksNode.get(prefKey, null); + isSaved = value != null; //password is saved if it is not the default value (because password length should be at least 6 + } + catch (StorageException e) + { + StudioLogger.debug("It was not possible to get if the " + prefKey + + " is saved or not"); + isSaved = false; + } + } + return isSaved; + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java new file mode 100644 index 0000000..f482d4c --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManager.java @@ -0,0 +1,328 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Saves the state of the {@link KeystoreManagerView} with:
+ * - the keystores mapped
+ * - the last backup date from a keystore
+ */
+class SaveStateManager
+{
+ private static final String FILE_COMMENT = "-- Signing and keys view persistence --";
+
+ private static final String STATE_FILENAME = "state.properties";
+
+ private final File persistenceFile = new File(System.getProperty("user.home") + File.separator
+ + "." + CertificateManagerActivator.PLUGIN_ID, STATE_FILENAME);
+
+ private static final String KEYSTORE_TYPE = "keystore_type=";
+
+ private static final String BACKUP_DATE = "backup_date=";
+
+ protected class ViewStateEntry
+ {
+ private final File keystoreFile;
+
+ private String keystoreType;
+
+ private Date backupDate;
+
+ public ViewStateEntry(File keystoreFile)
+ {
+
+ this.keystoreFile = keystoreFile;
+ }
+
+ public ViewStateEntry(File keystoreFile, String keystoreType)
+ {
+
+ this.keystoreFile = keystoreFile;
+ this.keystoreType = keystoreType;
+ }
+
+ /**
+ * @return the backupDate
+ */
+ public Date getBackupDate()
+ {
+ return backupDate;
+ }
+
+ /**
+ * @param backupDate the backupDate to set
+ */
+ public void setBackupDate(Date backupDate)
+ {
+ this.backupDate = backupDate;
+ }
+
+ /**
+ * @return the keystoreType
+ */
+ public String getKeystoreType()
+ {
+ return keystoreType;
+ }
+
+ /**
+ * @param keystoreType the keystoreType to set
+ */
+ public void setKeystoreType(String keystoreType)
+ {
+ this.keystoreType = keystoreType;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "ViewStateEntry [keystoreFile=" + keystoreFile + ", keystoreType="
+ + keystoreType + ", backupDate=" + backupDate + "]";
+ }
+
+ /**
+ * @return the keystoreFile
+ */
+ protected File getKeystoreFile()
+ {
+ return keystoreFile;
+ }
+ }
+
+ private static SaveStateManager _instance;
+
+ /**
+ * This class is a singleton.
+ * @return The unique instance of this class.
+ * */
+ public synchronized static SaveStateManager getInstance() throws IOException
+ {
+ if (_instance == null)
+ {
+ _instance = new SaveStateManager();
+ }
+ return _instance;
+ }
+
+ private SaveStateManager() throws IOException
+ {
+ //create folder if it does not exist
+ if (!persistenceFile.getParentFile().exists())
+ {
+ persistenceFile.getParentFile().mkdirs();
+ }
+ if (!persistenceFile.exists())
+ {
+ //init file
+ persistenceFile.createNewFile();
+ store(new Properties());
+ }
+ }
+
+ private String write(ViewStateEntry entry)
+ {
+ StringBuffer buffer = new StringBuffer();
+ if (entry.getKeystoreType() != null)
+ {
+ buffer.append(KEYSTORE_TYPE + entry.getKeystoreType() + File.pathSeparator);
+ }
+ if (entry.getBackupDate() != null)
+ {
+ buffer.append(BACKUP_DATE + entry.getBackupDate().getTime());
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * List all mapped keystores.
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public Set<File> getMappedKeystores() throws IOException
+ {
+ Set<File> mappedKeystores = new HashSet<File>();
+ Properties properties = load();
+ Enumeration<Object> enumeration = properties.keys();
+ while (enumeration.hasMoreElements())
+ {
+ Object k = enumeration.nextElement();
+ if (k instanceof String)
+ {
+ String key = (String) k;
+ File keystoreFile = new File(key);
+ mappedKeystores.add(keystoreFile);
+ }
+ }
+ return mappedKeystores;
+ }
+
+ /**
+ * Get a representation of the entry saved in the persistence.
+ * @param keystoreFile The file that will have its state retrieved.
+ * @return
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public ViewStateEntry getEntry(File keystoreFile) throws IOException
+ {
+ Properties properties = load();
+ Object v = properties.get(keystoreFile.getAbsolutePath());
+ ViewStateEntry entry = null;
+ if (v instanceof String)
+ {
+ String value = (String) v;
+ StringTokenizer stringTokenizer = new StringTokenizer(value, File.pathSeparator);
+ entry = new ViewStateEntry(keystoreFile);
+ while (stringTokenizer.hasMoreTokens())
+ {
+ String token = stringTokenizer.nextToken();
+ if (token.contains(KEYSTORE_TYPE))
+ {
+ token = token.substring(KEYSTORE_TYPE.length());
+ entry.setKeystoreType(token);
+ }
+ else if (token.contains(BACKUP_DATE))
+ {
+ token = token.substring(BACKUP_DATE.length());
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(Long.parseLong(token));
+ Date date = calendar.getTime();
+ entry.setBackupDate(date);
+ }
+ }
+ }
+ return entry;
+ }
+
+ /**
+ * Check if a keystore is mapped on the persistence mechanism.
+ * @param keystoreFile The keystore to be checked.
+ * @return true if keystore mapped, false otherwise
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public boolean isKeystoreMapped(File keystoreFile) throws IOException
+ {
+ Properties properties = load();
+ return properties.containsKey(keystoreFile.getAbsolutePath());
+ }
+
+ /**
+ * Adds (maps) a keystore.
+ * @param keystoreFile The keystore to be added to the persistence mechanism.
+ * @param keystoreType The type of the keystore.
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public void addEntry(File keystoreFile, String keystoreType) throws IOException
+ {
+ ViewStateEntry stateEntry = new ViewStateEntry(keystoreFile, keystoreType);
+ addEntry(keystoreFile, stateEntry);
+ }
+
+ private void addEntry(File keystoreFile, ViewStateEntry stateEntry) throws IOException
+ {
+ Properties prop = load();
+ prop.setProperty(keystoreFile.getAbsolutePath(), write(stateEntry));
+ store(prop);
+ }
+
+ /**
+ * Removes a keystore from the persistence mechanism.
+ * @param keystoreFile
+ * @throws IOException
+ */
+ public void removeEntry(File keystoreFile) throws IOException
+ {
+ Properties properties = load();
+ properties.remove(keystoreFile.getAbsolutePath());
+ store(properties);
+ }
+
+ /**
+ * Sets backup date from a keystore
+ * @param keystoreFile The keystore file.
+ * @param backupDate The date of the backup.
+ * @throws IOException If there are problems loading the persistence file.
+ */
+ public void setBackupDate(File keystoreFile, Date backupDate) throws IOException
+ {
+ ViewStateEntry entry = getEntry(keystoreFile);
+ entry.setBackupDate(backupDate);
+ addEntry(keystoreFile, entry);
+ }
+
+ private Properties load() throws IOException
+ {
+ FileInputStream in = null;
+ Properties props = new Properties();
+
+ try
+ {
+ in = new FileInputStream(persistenceFile);
+ props.loadFromXML(in);
+ }
+ finally
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ return props;
+ }
+
+ private void store(Properties prop) throws IOException
+ {
+ FileOutputStream out = null;
+
+ try
+ {
+ out = new FileOutputStream(persistenceFile);
+ prop.storeToXML(out, FILE_COMMENT);
+ }
+ finally
+ {
+ if (out != null)
+ {
+ try
+ {
+ out.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error("Could not close stream while saving properties. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java new file mode 100644 index 0000000..9376d47 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/core/SaveStateManagerTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.core; + +import java.io.File; +import java.util.Calendar; +import java.util.Date; + +import junit.framework.TestCase; + +import org.junit.Test; + +/** + * See {@link SaveStateManager} + */ +public class SaveStateManagerTest extends TestCase +{ + private static final String JKS = "JKS"; + + SaveStateManager manager; + + File adtKeystoreFile = null; + + File motodevKeystoreFile = null; + + /* (non-Javadoc) + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception + { + manager = SaveStateManager.getInstance(); + adtKeystoreFile = new File("C:\\Users\\gdpr78\\motodevstudio\\tools\\adt.keystore"); + motodevKeystoreFile = new File("C:\\Users\\gdpr78\\motodevstudio\\tools\\motodev.keystore"); + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception + { + super.tearDown(); + manager.removeEntry(adtKeystoreFile); + manager.removeEntry(motodevKeystoreFile); + } + + @Test + public void testAddEntryWithoutBackupDate() + { + try + { + manager.addEntry(adtKeystoreFile, JKS); + + SaveStateManager.ViewStateEntry entry = manager.getEntry(adtKeystoreFile); + + assert ((entry != null) && (entry.getKeystoreFile() != null) && entry.getKeystoreFile() + .equals(adtKeystoreFile)); + assert ((entry != null) && (entry.getKeystoreType() != null) && entry.getKeystoreType() + .equals(JKS)); + } + catch (Exception e) + { + //error + assert (false); + } + } + + @Test + public void testListKeystoresMapped() + { + try + { + manager.addEntry(adtKeystoreFile, JKS); + manager.addEntry(motodevKeystoreFile, "JKS"); + + assert ((manager.getMappedKeystores() != null) + && (manager.getMappedKeystores().size() == 2) + && manager.getMappedKeystores().contains(adtKeystoreFile) && manager + .getMappedKeystores().contains(motodevKeystoreFile)); + } + catch (Exception e) + { + //error + assert (false); + } + } + + @Test + public void testSetBackupDate() + { + try + { + Date date = Calendar.getInstance().getTime(); + manager.addEntry(adtKeystoreFile, JKS); + manager.setBackupDate(adtKeystoreFile, date); + + SaveStateManager.ViewStateEntry entry = manager.getEntry(adtKeystoreFile); + + assert ((entry != null) && (entry.getBackupDate() != null) && entry.getBackupDate() + .equals(date)); + } + catch (Exception e) + { + //error + assert (false); + } + } + + @Test + public void testIsMappedKeystore() + { + try + { + manager.addEntry(adtKeystoreFile, JKS); + boolean result = manager.isKeystoreMapped(adtKeystoreFile); + assert (result == true); + } + catch (Exception e) + { + //error + assert (false); + } + } + + @Test + public void testRemoveEntry() + { + try + { + manager.addEntry(motodevKeystoreFile, "JKS"); + assert (manager.isKeystoreMapped(motodevKeystoreFile) == true); + + manager.removeEntry(motodevKeystoreFile); + assert (manager.isKeystoreMapped(motodevKeystoreFile) == false); + } + catch (Exception e) + { + //error + assert (false); + } + } + +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java new file mode 100644 index 0000000..19e24a4 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/IKeyStoreModelListener.java @@ -0,0 +1,62 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.event;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This interface must be implemented by listeners to events occurred on the {@link ITreeNode}.
+ */
+public interface IKeyStoreModelListener
+{
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to add a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be added.
+ */
+ public void handleNodeAdditionEvent(KeyStoreModelEvent keyStoreModeEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to remove a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be added.
+ */
+ public void handleNodeRemovalEvent(KeyStoreModelEvent keyStoreModeEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to update a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be added.
+ */
+ public void handleNodeUpdateEvent(KeyStoreModelEvent keyStoreModeEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to collapse a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be collapsed.
+ */
+ public void handleNodeCollapseEvent(KeyStoreModelEvent keyStoreModelEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to refresh a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be refreshed.
+ */
+ public void handleNodeRefreshEvent(KeyStoreModelEvent keyStoreModelEvent);
+
+ /**
+ * Handles the event {@link KeyStoreModelEvent#EventType} to clear a node.
+ * @param keyStoreModelEvent {@link KeyStoreModelEvent#getTreeNodeItem()} contains the node to be cleared.
+ */
+ public void handleNodeClearEvent(KeyStoreModelEvent keyStoreModelEvent);
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java new file mode 100644 index 0000000..9ff4dd0 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEvent.java @@ -0,0 +1,67 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.event;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * This class represents an event occurred on the {@link ITreeNode}.
+ */
+public class KeyStoreModelEvent
+{
+ private final EventType eventType;
+
+ private final ITreeNode treeNodeItem;
+
+ /**
+ * Represents the change in the model. The {@link KeyStoreModelEvent#treeNodeItem} in each event may vary as specified below:
+ * <ul>
+ * <li>{@link EVENT_TYPE#ADD} it is the item that needs to be added</li>
+ * <li>{@link EVENT_TYPE#REMOVE} it is the item that needs to be deleted</li>
+ * <li>{@link EVENT_TYPE#UPDATE} it is the item that needs to be updated</li>
+ * </ul>
+ */
+ public enum EventType
+ {
+ ADD, REMOVE, UPDATE, COLLAPSE, REFRESH, CLEAR
+ }
+
+ /**
+ * Returns the event type.
+ * */
+ public EventType getEventType()
+ {
+ return eventType;
+ }
+
+ /**
+ * Returns the tree node item related to the event.
+ * */
+ public ITreeNode getTreeNodeItem()
+ {
+ return treeNodeItem;
+ }
+
+ /**
+ * Constructs a new event given an {@link ITreeNode} and a {@link KeyStoreModelEvent#EventType}.
+ * */
+ public KeyStoreModelEvent(ITreeNode treeNodeItem, EventType eventType)
+ {
+ this.eventType = eventType;
+ this.treeNodeItem = treeNodeItem;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java new file mode 100644 index 0000000..5e2b49b --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/event/KeyStoreModelEventManager.java @@ -0,0 +1,116 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Manager which notifies {@link IKeyStoreModelListener} registered that a {@link KeyStoreModelEvent} occurred.
+ * It is a singleton that needs to be called by the hierarchy of {@link ITreeNode} items when they modify the {@link ITreeNode}.
+ */
+public class KeyStoreModelEventManager
+{
+ private static KeyStoreModelEventManager _instance;
+
+ private final List<IKeyStoreModelListener> listeners = new ArrayList<IKeyStoreModelListener>();
+
+ private KeyStoreModelEventManager()
+ {
+ // Singleton - private default constructor prevents instantiations by other classes.
+ }
+
+ /**
+ * Return the singleton instance of KeyStoreModelEventManager.
+ * */
+ public synchronized static KeyStoreModelEventManager getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new KeyStoreModelEventManager();
+ }
+ return _instance;
+ }
+
+ /**
+ * Add the parameter {@code listener} to the list of KeyStore event listeners.
+ * @param listener The listener to be added.
+ * */
+ public void addListener(IKeyStoreModelListener listener)
+ {
+ synchronized (listener)
+ {
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the parameter {@code listener} to the list of KeyStore event listeners.
+ * @param listener The listener to be removed.
+ * */
+ public void removeListener(IKeyStoreModelListener listener)
+ {
+ synchronized (listener)
+ {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Fire/notify/deliver the event to registered listeners.
+ * @param node {@link ITreeNode} that needs to refresh the view based on the model
+ * @param eventType Event that occurred.
+ */
+ public void fireEvent(ITreeNode treeNodeItem, KeyStoreModelEvent.EventType eventType)
+ {
+ KeyStoreModelEvent keyStoreModelEvent = new KeyStoreModelEvent(treeNodeItem, eventType);
+ synchronized (listeners)
+ {
+ if (listeners != null)
+ {
+ for (IKeyStoreModelListener listener : listeners)
+ {
+ switch (eventType)
+ {
+ case ADD:
+ listener.handleNodeAdditionEvent(keyStoreModelEvent);
+ break;
+ case REMOVE:
+ listener.handleNodeRemovalEvent(keyStoreModelEvent);
+ break;
+ case UPDATE:
+ listener.handleNodeUpdateEvent(keyStoreModelEvent);
+ break;
+ case COLLAPSE:
+ listener.handleNodeCollapseEvent(keyStoreModelEvent);
+ break;
+ case REFRESH:
+ listener.handleNodeRefreshEvent(keyStoreModelEvent);
+ break;
+ case CLEAR:
+ listener.handleNodeClearEvent(keyStoreModelEvent);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java new file mode 100644 index 0000000..66e69bc --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/InvalidPasswordException.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.exception; + +import com.motorola.studio.android.common.exception.AndroidException; + +/** + * Exception thrown when the password to access a keystore is invalid or wrong. + * */ +@SuppressWarnings("serial") +public class InvalidPasswordException extends AndroidException +{ + + /* + * Create a new empty exception. + * */ + @SuppressWarnings("unused") + private InvalidPasswordException() + { + //prevent methods to throw this exception without further information + } + + /** + * Create a new exception with a message indicating the problem. + * */ + public InvalidPasswordException(String message) + { + super(message); + } + + /** + * Create a new exception with a message indicating the problem, + * and append some other exception that is being replaced by this one. + * */ + public InvalidPasswordException(String message, Throwable cause) + { + super(message, cause); + } + +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java new file mode 100644 index 0000000..4252691 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/exception/KeyStoreManagerException.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.exception; + +import com.motorola.studio.android.common.exception.AndroidException; +import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager; + +/** + * Exception thrown when trying to access the {@link KeyStoreManager}. + * */ +@SuppressWarnings("serial") +public class KeyStoreManagerException extends AndroidException +{ + /* + * Create a new empty exception. + * */ + @SuppressWarnings("unused") + private KeyStoreManagerException() + { + //prevent methods to throw this exception without further information + } + + /** + * Create a new exception with a message indicating the problem. + * */ + public KeyStoreManagerException(String message) + { + super(message); + } + + /** + * Create a new exception with a message indicating the problem, + * and append some other exception that is being replaced by this one. + * */ + public KeyStoreManagerException(String message, Throwable cause) + { + super(message, cause); + } + +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java new file mode 100644 index 0000000..26fc44f --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/CertificateManagerNLS.java @@ -0,0 +1,522 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.i18n;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * This class is the NLS component for Certificate Manager plug-in
+ */
+public class CertificateManagerNLS extends NLS
+{
+
+ public static String AbstractTreeNode_SavedPassword_Tooltip;
+
+ public static String AbstractTreeNode_UnsavedPassword_Tooltip;
+
+ public static String BackupDialog_Archive_Exists_Message;
+
+ public static String BackupDialog_Archive_Exists_Title;
+
+ public static String BackupDialog_Backup_File;
+
+ public static String BackupDialog_Browse;
+
+ public static String BackupDialog_Default_Message;
+
+ public static String BackupDialog_Diag_Title;
+
+ public static String BackupDialog_DialogTitle;
+
+ public static String BackupDialog_Fail_Writing_Archive_Message;
+
+ public static String BackupDialog_Fail_Writing_Archive_Title;
+
+ public static String BackupDialog_Invalid_Destination_Message;
+
+ public static String BackupDialog_Invalid_Destination_Title;
+
+ public static String BackupDialog_KeyStores;
+
+ public static String BackupDialog_Non_Absolute_Path;
+
+ public static String BackupDialog_Path;
+
+ public static String BackupDialog_Select_All;
+
+ public static String BackupDialog_Select_KeyStore;
+
+ public static String BackupHandler_Error_BackUp_Title;
+
+ public static String BackupHandler_Error_Setting_Date;
+
+ public static String BackupHandler_Error_Writing_Archive;
+
+ public static String SelectExistentKeystorePage_CheckboxText_AlsoImportIntoSigningView;
+
+ public static String SelectExistentKeystorePage_KeystorePasswordLabel;
+
+ public static String SelectExistentKeystorePage_WizardPageMessage;
+
+ public static String SelectExistentKeystorePage_WizardPageTitle;
+
+ public static String SelectExistentKeystoreWizard_BrowseExistentKeystore_PageTitle;
+
+ public static String SelectExistentKeystoreWizard_Error_InvalidPassword;
+
+ public static String SelectExistentKeystoreWizard_Error_KeystoreType;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_LOAD;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_NO_CERTIFICATE_ERROR;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_OPERATION;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_ERROR;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_ERROR;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_OPERATION;
+
+ public static String UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY;
+
+ public static String PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON;
+
+ public static String PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON;
+
+ public static String PasswordProvider_DialogTitle;
+
+ public static String PasswordProvider_Error_WhileRemovingPassword;
+
+ public static String PasswordProvider_Error_WhileSaving;
+
+ public static String PasswordProvider_MessageLabel;
+
+ public static String PasswordProvider_PasswordLabel;
+
+ public static String PasswordProvider_SaveThisPassword;
+
+ public static String PasswordProvider_Key_MessageLabel;
+
+ public static String RemoveExternalPackageSignaturePage_Package_Tree_Label;
+
+ public static String RestoreBackupDialog_BackUp_File;
+
+ public static String RestoreBackupDialog_BackUpFile_Not_Exist;
+
+ public static String RestoreBackupDialog_Browse_Button;
+
+ public static String RestoreBackupDialog_Default_Message;
+
+ public static String RestoreBackupDialog_Destination;
+
+ public static String RestoreBackupDialog_Dialog_Title;
+
+ public static String RestoreBackupDialog_Error_Loading_Entries;
+
+ public static String RestoreBackupDialog_Invalid_Dest_Path;
+
+ public static String RestoreBackupDialog_KeyStores;
+
+ public static String RestoreBackupDialog_Path_Group;
+
+ public static String RestoreBackupDialog_Select_All;
+
+ public static String RestoreBackupDialog_Select_KeyStore;
+
+ public static String RestoreBackupDialog_TitleArea_Message;
+
+ public static String RestoreBackupHandler_Error_Mapping_Message;
+
+ public static String RestoreBackupHandler_Error_Mapping_Status;
+
+ public static String RestoreBackupHandler_Error_Mapping_Title;
+
+ public static String RestoreBackupHandler_Error_Restoring_Backup_Message;
+
+ public static String RestoreBackupHandler_Error_Restoring_Backup_Status;
+
+ public static String RestoreBackupHandler_Error_Restoring_Backup_Title;
+
+ public static String RestoreBackupHandler_RestoreIssue_MissingMetadataFile_WarningDescription;
+
+ public static String RestoreBackupHandler_RestoreIssue_WarningTitle;
+
+ public static String READ_ONLY_TEXT;
+
+ public static String SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG;
+
+ public static String SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE;
+
+ public static String DeleteKeystoreHandler_ConfirmationQuestionDialog_Description;
+
+ public static String DeleteKeystoreHandler_ConfirmationQuestionDialog_Title;
+
+ public static String DeleteKeystoreHandler_ConfirmationQuestionDialog_Toggle;
+
+ public static String DeleteKeystoreHandler_Delete_Selected_Keystores;
+
+ public static String ImportKeyStoreDialog_Alias_Column;
+
+ public static String ImportKeyStoreDialog_Default_Message;
+
+ public static String ImportKeyStoreDialog_Dialog_Title;
+
+ public static String ImportKeyStoreDialog_Error_Loading_Entries;
+
+ public static String ImportKeyStoreDialog_Error_Loading_Keystores;
+
+ public static String ImportKeyStoreDialog_Invalid_Keystore_Passwd;
+
+ public static String ImportKeyStoreDialog_KeyStore_Label;
+
+ public static String ImportKeyStoreDialog_Load_Button;
+
+ public static String ImportKeyStoreDialog_No_Entries_To_Import;
+
+ public static String ImportKeyStoreDialog_Passwd_Column;
+
+ public static String ImportKeyStoreDialog_Password_Label;
+
+ public static String ImportKeyStoreDialog_Select_Source_Ks;
+
+ public static String ImportKeyStoreDialog_Select_Target_Kesytore;
+
+ public static String ImportKeyStoreDialog_Source_Group;
+
+ public static String ImportKeyStoreDialog_Target_Group;
+
+ public static String ImportKeyStoreDialog_Type_SourceKs_Passwd;
+
+ public static String ImportKeyStoreDialog_Verified_Column;
+
+ public static String ImportKeyStoreDialog_Verified_Pass_Wrong;
+
+ public static String ImportKeyStoreDialog_Verified_Pass_Yes;
+
+ public static String ImportKeyStoreDialog_Wrong_Entries_Passwd;
+
+ public static String ImportKeystorePage_CouldNotImportKeystore;
+
+ public static String ImportKeystorePage_Description;
+
+ public static String ImportKeystorePage_DirectoryNotAllowedErrorMsg;
+
+ public static String ImportKeystorePage_FileDoesNotExist;
+
+ public static String ImportKeystorePage_FilenameCannotBeEmpty;
+
+ public static String ImportKeystorePage_KeystoreAlreadyMapped;
+
+ public static String ImportKeystorePage_KeystoreTypeCannotBeEmpty;
+
+ public static String ImportKeystorePage_Title;
+
+ public static String ImportKeystoreWizard_ImportKeystore;
+
+ public static String ImportKeystorePage_FileEmpty;
+
+ public static String DeleteKeyHandler_ConfirmationQuestionDialog_Description;
+
+ public static String DeleteKeyHandler_ConfirmationQuestionDialog_Title;
+
+ public static String DeleteKeyHandler_Delete_Selected_Keys;
+
+ /**
+ * The bundle location.
+ * It refers to messages.properties file inside this package
+ */
+ static
+ {
+ NLS.initializeMessages(
+ "com.motorolamobility.studio.android.certmanager.i18n.certificateManagerNLS",
+ CertificateManagerNLS.class);
+ }
+
+ public static String CertificateManagerView_ExpiresIn_ColumnName;
+
+ public static String CertificateManagerView_LastBackupDate_ColumnName;
+
+ public static String CertificateManagerView_NameAlias_ColumnName;
+
+ public static String CertificateManagerView_Type_ColumnName;
+
+ public static String CertificateManagerView_Path_ColumnName;
+
+ public static String CreateKeystorePage_ConfirmFileOverwrite;
+
+ public static String CreateKeystorePage_ConfirmPasswordInfoMsg;
+
+ public static String CreateKeystorePage_ConfirmReplaceFile;
+
+ public static String CreateKeystorePage_CouldNotSavePassword;
+
+ public static String CreateKeystorePage_CreateKeystore;
+
+ public static String CreateKeystorePage_DefaultKeystoreFilename;
+
+ public static String CreateKeystorePage_DefaultKeystoreFilenameExtension;
+
+ public static String CreateKeystorePage_ErrorCreatingKeystore;
+
+ public static String CreateKeystorePage_ErrorOnKeyStoreFileCreation;
+
+ public static String CreateKeystorePage_FilenameSyntaxError;
+
+ public static String CreateKeystorePage_KeystoreConfirmPasswordLabel;
+
+ public static String CreateKeystorePage_KeystoreFilenameBrowse;
+
+ public static String CreateKeystorePage_KeystoreFilenameLabel;
+
+ public static String CreateKeystorePage_KeystorePasswordLabel;
+
+ public static String CreateKeystorePage_KeystoreType;
+
+ public static String CreateKeystorePage_PasswordDoesNotMatch;
+
+ public static String CreateKeystorePage_PasswordMinSizeMessage;
+
+ public static String CreateKeystorePage_SaveThisPassword;
+
+ public static String CreateKeystorePage_SetKeystoreType;
+
+ public static String CreateKeystorePage_SetPasswordInfoMsg;
+
+ public static String CreateKeystorePage_UseKeystoreTypeAsExtension;
+
+ public static String CreateKeystorePage_WizardDefaultMessage;
+
+ public static String CreateKeystoreWizard_CreateNewKeyStore;
+
+ /*
+ * CertificateBlock
+ */
+ public static String CertificateBlock_AliasName;
+
+ public static String CertificateBlock_BasicInfoGroupTitle;
+
+ public static String CertificateBlock_FirstAndLastName;
+
+ public static String CertificateBlock_Organization;
+
+ public static String CertificateBlock_OrganizationUnit;
+
+ public static String CertificateBlock_CityOrLocality;
+
+ public static String CertificateBlock_StateOrProvince;
+
+ public static String CertificateBlock_ConfirmKeyPassword_Label;
+
+ public static String CertificateBlock_EnterPassword_InfoMessage;
+
+ public static String CertificateBlock_CountryCode;
+
+ public static String CertificateBlock_FieldIsEmpty;
+
+ public static String CertificateBlock_Validity;
+
+ public static String CertificateBlock_Validity_Error;
+
+ public static String CertificateBlock_ExpirationDate;
+
+ public static String CertificateBlock_KeyPassword_Label;
+
+ public static String CertificateBlock_KeyTooltip;
+
+ public static String CertificateInfoDialog_NotAvailableProperty;
+
+ public static String CertificateInfoDialog_ShellTitle;
+
+ public static String CertificateInfoDialog_UnknownCertificateKeypairType;
+
+ /*
+ * Certificate properties handler
+ */
+ public static String CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties;
+
+ public static String CreateKeyWizard_ErrorCreatingKey_DialogTitle;
+
+ /*
+ * Create self signed wizard page
+ */
+ public static String CreateSelfSignedCertificateWizardPage_Description;
+
+ public static String CreateSelfSignedCertificateWizardPage_Title;
+
+ public static String KeystoreManagerView_ErrorImportingBackwardKeystore;
+
+ public static String KeystoreManagerView_ErrorLoadingMappedKeystoresFromPersistence;
+
+ public static String KeyStoreModel_Error_GettingAliasesFromKeystore;
+
+ public static String KeyStoreNode_CouldNotGetKeyStorePassword;
+
+ public static String KeyStoreNode_CouldNotLoadKeystore_Tooltip;
+
+ public static String KeyStoreNode_ErrorKeystoreNotFound;
+
+ public static String KeyStoreNode_IncorrectPasswordToDeleteEntries_Error;
+
+ public static String KeyStoreNode_InvalidPassword;
+
+ public static String KeyStoreNode_KeyPairNotMapped_Message;
+
+ public static String KeyStoreNode_KeyPairNotMapped_Title;
+
+ public static String KeyStoreNode_KeyPairNotMapped_LogMessage;
+
+ public static String KeyStoreNode_KeystoreFileNotFound;
+
+ public static String KeyStoreNode_KeystoreTypeWrong_NodeStatus;
+
+ public static String KeyStoreNode_NotFoundOrIncorrectPasswordToDeleteEntry;
+
+ public static String KeyStoreNode_Password_NotNull;
+
+ public static String KeyStoreNode_UseRefresh_StatusNode;
+
+ public static String KeyStoreNode_Wrong_KeystoreType_Message;
+
+ public static String KeyStoreNode_Wrong_KeystoreType_Title;
+
+ public static String KeyStoreRootNode_Error_AlreadyMappedKeystorePath;
+
+ public static String KeyStoreUtils_RSA_Keys_Expected;
+
+ public static String KeyStoreUtils_Error_AddEntryToKeyStore;
+
+ public static String KeyStoreUtils_Error_WriteKeyStore;
+
+ public static String SIGN_WIZARD_AREA_SIGN_KEYSTORE_LABEL;
+
+ public static String SIGN_WIZARD_AREA_SIGN_KEYS_LABEL;
+
+ public static String KeyStoreUtils_Error_DeleteKeyStore;
+
+ public static String KeyStoreUtils_Error_FileAlreadyExists;
+
+ public static String KeyStoreUtils_Error_LoadKeyStore;
+
+ public static String KeyStoreUtils_ErrorDeletingAlias;
+
+ public static String CertificatePeriodExpired_Issue;
+
+ public static String CertificatePeriodNotYeatValid_Issue;
+
+ public static String ChangePasswordKeyHandler_Error_WrongOldKeyPassword;
+
+ public static String ChangePasswordKeyHandler_Wrong_Key_Password;
+
+ public static String ChangePasswordKeystoreHandler_Error_ChangingKeystorePassword;
+
+ public static String ChangePasswordKeystoreHandler_Error_WrongOldKeystorePassword;
+
+ public static String ChangePasswordKeystoreHandler_InvalidOldPassword;
+
+ public static String EntryNode_ErrorGettingCertificateFromEntry;
+
+ public static String EntryNode_NotFoundOrTypeWrong;
+
+ public static String Passwordinput_EnterOldKeystorePasssword_Message;
+
+ public static String PasswordChanged_Info_Title;
+
+ public static String PasswordChanged_Info_Message;
+
+ public static String PasswordInput_EnterOldKeyPasssword_Message;
+
+ public static String PasswordChanged_KeyInfo_Message;
+
+ public static String PasswordChanged_InvalidKeystorePassword;
+
+ public static String CertificateBlock_CreationDate;
+
+ public static String CertificateBlock_DetailedInfoGroupTitle;
+
+ public static String CertificateBlock_DetailedInfoNonEmptyFieldsRestriction;
+
+ public static String ConvertKeyStoreTypeDialog_Alias_Column;
+
+ public static String ConvertKeyStoreTypeDialog_Choose_KeyStore_Msg;
+
+ public static String ConvertKeyStoreTypeDialog_Choose_New_Type_Msg;
+
+ public static String ConvertKeyStoreTypeDialog_CouldNotLoad_Keystores_Error;
+
+ public static String ConvertKeyStoreTypeDialog_DefaultMessage;
+
+ public static String ConvertKeyStoreTypeDialog_DialogTitle;
+
+ public static String ConvertKeyStoreTypeDialog_Entries_Group;
+
+ public static String ConvertKeyStoreTypeDialog_Error_Loading_Keystore;
+
+ public static String ConvertKeyStoreTypeDialog_Incorrect_Entry_Pass;
+
+ public static String ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass;
+
+ public static String ConvertKeyStoreTypeDialog_KeyStoreLabel;
+
+ public static String ConvertKeyStoreTypeDialog_Load_Button;
+
+ public static String ConvertKeyStoreTypeDialog_NewType_Label;
+
+ public static String ConvertKeyStoreTypeDialog_Original_Type_Label;
+
+ public static String ConvertKeyStoreTypeDialog_Password_Column;
+
+ public static String ConvertKeyStoreTypeDialog_Password_Label;
+
+ public static String ConvertKeyStoreTypeDialog_Verified_Column;
+
+ public static String ConvertKeyStoreTypeDialog_Verified_Pass_Wrong;
+
+ public static String ConvertKeyStoreTypeDialog_Verified_Pass_Yes;
+
+ public static String NewKeyBlock_PasswordGroupTitle;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_CHOOSE;
+
+ public static String SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE;
+
+ public static String SignExternalPackagePage_Package_Tree_Label;
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties new file mode 100644 index 0000000..4481dee --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/i18n/certificateManagerNLS.properties @@ -0,0 +1,285 @@ +#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# 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.
+#
+
+AbstractTreeNode_SavedPassword_Tooltip=[password saved]
+AbstractTreeNode_UnsavedPassword_Tooltip=[password not saved]
+BackupDialog_Archive_Exists_Message=The chosen destination file, {0}, already exists.\nDo you want to overwrite it?
+BackupDialog_Archive_Exists_Title=File already exists.
+BackupDialog_Backup_File=Backup File
+BackupDialog_Browse=Browse...
+BackupDialog_Default_Message=Specify an archive (zip) file and the keystores that should be backed up to that archive
+BackupDialog_Diag_Title=Back Up Keystores
+BackupDialog_DialogTitle=Back up keystores
+BackupDialog_Fail_Writing_Archive_Message=Can't write to file {0}.\nVerify that the path is valid, you have the right permissions and that the file has not been opened by another program.
+BackupDialog_Fail_Writing_Archive_Title=Unable to Write Archive
+BackupDialog_Invalid_Destination_Message=The archive file is invalid. It should be a zip file.
+BackupDialog_Invalid_Destination_Title=Invalid Archive File
+BackupDialog_KeyStores=Keystores
+BackupDialog_Non_Absolute_Path=Selected path is not absolute. Backup archive will be created at:\n{0}
+BackupDialog_Path=Path:
+BackupDialog_Select_All=Select all
+BackupDialog_Select_KeyStore=Select at least one keystore.
+BackupHandler_Error_BackUp_Title=Error while creating keystore backup
+BackupHandler_Error_Setting_Date=Could not set backup dates
+BackupHandler_Error_Writing_Archive=Unable to write archive file {0}
+
+ImportKeyStoreDialog_Alias_Column=Alias
+ImportKeyStoreDialog_Default_Message=Import selected keys (entries) from one keystore to another.
+ImportKeyStoreDialog_Dialog_Title=Import Entries
+ImportKeyStoreDialog_Error_Loading_Entries=An error has occurred while attempting to load source keystore entries.
+ImportKeyStoreDialog_Error_Loading_Keystores=Could not load mapped keystores
+ImportKeyStoreDialog_Invalid_Keystore_Passwd=Invalid source keystore password.
+ImportKeyStoreDialog_KeyStore_Label=Keystore:
+ImportKeyStoreDialog_Load_Button=Load
+ImportKeyStoreDialog_No_Entries_To_Import=Select at least one entry to import
+ImportKeyStoreDialog_Passwd_Column=Password
+ImportKeyStoreDialog_Password_Label=Password:
+ImportKeyStoreDialog_Select_Source_Ks=Select a source keystore
+ImportKeyStoreDialog_Select_Target_Kesytore=Select a target keystore
+ImportKeyStoreDialog_Source_Group=Source Keystore
+ImportKeyStoreDialog_Target_Group=Target Keystore
+ImportKeyStoreDialog_Type_SourceKs_Passwd=Enter the source keystore password.
+ImportKeyStoreDialog_Verified_Column=Verified
+ImportKeyStoreDialog_Verified_Pass_Wrong=Not verified
+ImportKeyStoreDialog_Verified_Pass_Yes=Yes
+ImportKeyStoreDialog_Wrong_Entries_Passwd=Supply the correct passwords for the entries being imported.
+ImportKeystorePage_CouldNotImportKeystore=Could not import keystore
+ImportKeystorePage_Description=Import an existing keystore into Signing and Keys view.
+ImportKeystorePage_DirectoryNotAllowedErrorMsg={0} is a directory
+ImportKeystorePage_FileDoesNotExist=The keystore file {0} does not exist.
+ImportKeystorePage_FileEmpty=The keystore file {0} is empty.
+ImportKeystorePage_FilenameCannotBeEmpty=Filename cannot be empty.
+ImportKeystorePage_KeystoreAlreadyMapped=The keystore file {0} is already present in the Signing and Keys view.
+ImportKeystorePage_KeystoreTypeCannotBeEmpty=Keystore type cannot be empty.
+ImportKeystorePage_Title=Import Keystore
+ImportKeystoreWizard_ImportKeystore=Import an existing keystore into the Signing and Keys view
+DeleteKeystoreHandler_ConfirmationQuestionDialog_Description=Delete keystore {0}?\nNOTE: consider making a backup before deleting this keystore.
+DeleteKeystoreHandler_ConfirmationQuestionDialog_Title=Delete Keystore
+DeleteKeystoreHandler_ConfirmationQuestionDialog_Toggle=Delete content on disk? (Cannot be undone).
+DeleteKeystoreHandler_Delete_Selected_Keystores=Delete selected keystores?\nNOTE: consider making a backup before deleting keystores.
+
+CertificateManagerView_ExpiresIn_ColumnName=Expires on
+CertificateManagerView_LastBackupDate_ColumnName=Last backup date
+CertificateManagerView_NameAlias_ColumnName=Name (Alias)
+CertificateManagerView_Type_ColumnName=Type
+CertificateManagerView_Path_ColumnName=Path
+
+DeleteKeyHandler_ConfirmationQuestionDialog_Description=Delete key {0}? (Cannot be undone).\nNOTE: consider making a backup before deleting this key.
+DeleteKeyHandler_ConfirmationQuestionDialog_Title=Delete Key
+DeleteKeyHandler_Delete_Selected_Keys=Delete selected keys? (Cannot be undone).\nNOTE: consider making a backup before deleting this key.
+
+#------------------------------------------------------------------------------
+# Create keystore Wizard
+#------------------------------------------------------------------------------
+CreateKeystorePage_ConfirmFileOverwrite=Confirm File Overwrite
+CreateKeystorePage_ConfirmPasswordInfoMsg=Confirm the password.
+CreateKeystorePage_ConfirmReplaceFile={0} already exists.\nDo you want to replace it?
+CreateKeystorePage_CouldNotSavePassword=Could not save password
+CreateKeystorePage_CreateKeystore=Create Keystore
+CreateKeystorePage_DefaultKeystoreFilename=keystore_{0}
+CreateKeystorePage_DefaultKeystoreFilenameExtension=keystore
+CreateKeystorePage_ErrorCreatingKeystore=Error creating keystore
+CreateKeystorePage_ErrorOnKeyStoreFileCreation=Error writing file \"{0}\" to disk. Check filename syntax and file system permissions.
+CreateKeystorePage_FilenameSyntaxError=The filename, directory name, or volume label syntax is incorrect.
+CreateKeystorePage_KeystoreConfirmPasswordLabel=Confirm Password:
+CreateKeystorePage_KeystoreFilenameBrowse=Browse...
+CreateKeystorePage_KeystoreFilenameLabel=Keystore Filename:
+CreateKeystorePage_KeystorePasswordLabel=Keystore Password:
+CreateKeystorePage_KeystoreType=Keystore Type:
+CreateKeystorePage_PasswordDoesNotMatch=Password does not match.
+CreateKeystorePage_PasswordMinSizeMessage=Password must have at least {0} characters.
+CreateKeystorePage_SaveThisPassword=Save this password
+CreateKeystorePage_SetKeystoreType=Set a keystore type.
+CreateKeystorePage_SetPasswordInfoMsg=Set a keystore password.
+CreateKeystorePage_UseKeystoreTypeAsExtension=Use keystore type as keystore filename extension
+CreateKeystorePage_WizardDefaultMessage=A keystore is an encrypted file protected by a password that groups key pairs - public/private keys.
+CreateKeystoreWizard_CreateNewKeyStore=Create Keystore
+
+#------------------------------------------------------------------------------
+# CertificateBlock
+#------------------------------------------------------------------------------
+CertificateBlock_AliasName=Alias name
+CertificateBlock_BasicInfoGroupTitle=Basic Info
+CertificateBlock_FirstAndLastName=First and Last Name
+CertificateBlock_Organization=Organization
+CertificateBlock_OrganizationUnit=Organization Unit
+CertificateBlock_CityOrLocality=City or Locality
+CertificateBlock_StateOrProvince=State or Province
+CertificateBlock_ConfirmKeyPassword_Label=Confirm Password
+CertificateBlock_EnterPassword_InfoMessage=Enter keystore password
+CertificateBlock_CountryCode=Country Code (XX)
+CertificateBlock_FieldIsEmpty={0} cannot be empty.
+CertificateBlock_Validity=Validity (years)
+CertificateBlock_Validity_Error=Validity should be a positive integer value.
+CertificateBlock_ExpirationDate=Expiration Date
+CertificateBlock_KeyPassword_Label=Key Password
+CertificateBlock_KeyTooltip=Organization: {0}\nFirst and Last Name: {1}
+CertificateInfoDialog_NotAvailableProperty=Not available
+CertificateInfoDialog_ShellTitle=Key Properties
+CertificateInfoDialog_UnknownCertificateKeypairType=Unknown key type
+CertificateBlock_CreationDate=Creation Date
+CertificateBlock_DetailedInfoGroupTitle=Detailed Info
+CertificateBlock_DetailedInfoNonEmptyFieldsRestriction=Validity and at least one other piece of detailed information must be supplied.
+
+#------------------------------------------------------------------------------
+# Certificate Properties Handler
+#------------------------------------------------------------------------------
+CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties=Error getting key properties
+
+#------------------------------------------------------------------------------
+# Create Self Signed wizard page
+#------------------------------------------------------------------------------
+CreateKeyWizard_ErrorCreatingKey_DialogTitle=Error creating key
+CreateSelfSignedCertificateWizardPage_Description=Provide the self-signed key information. Required fields are marked with '*'.
+CreateSelfSignedCertificateWizardPage_Title=Create Self-Signed Key
+KeystoreManagerView_ErrorImportingBackwardKeystore=Could not import the old MOTODEV keystore (for backward compatibility) from {0}
+KeystoreManagerView_ErrorLoadingMappedKeystoresFromPersistence=Error loading mapped keystores
+KeyStoreModel_Error_GettingAliasesFromKeystore=Cannot get aliases from keystore {0}.
+KeyStoreNode_CouldNotGetKeyStorePassword=Could not get keystore password:
+KeyStoreNode_CouldNotLoadKeystore_Tooltip=Could not load keystore file. Use Refresh to try again.
+KeyStoreNode_ErrorKeystoreNotFound=Keystore file not found
+KeyStoreNode_IncorrectPasswordToDeleteEntries_Error=Incorrect password
+KeyStoreNode_InvalidPassword=Invalid password. Try again.
+KeyStoreNode_KeyPairNotMapped_LogMessage=Entry with alias: {0} is a key pair, which is not supported for this view.
+KeyStoreNode_KeyPairNotMapped_Message=Keystore contains unsupported entries. Check log for details.
+KeyStoreNode_KeyPairNotMapped_Title=Entry not mapped
+KeyStoreNode_KeystoreFileNotFound=Keystore file not found
+KeyStoreNode_KeystoreTypeWrong_NodeStatus=Keystore type is wrong. Re-import keystore with the correct type.
+KeyStoreNode_NotFoundOrIncorrectPasswordToDeleteEntry=Password not found or incorrect when deleting entry with alias:
+KeyStoreNode_Password_NotNull=Password cannot be null
+KeyStoreNode_UseRefresh_StatusNode=Unable to read keystore. Refresh, and try again.
+KeyStoreNode_Wrong_KeystoreType_Message=The keystore {0} has been mapped with the incorrect type JCEKS. Keystore type has been changed to the correct type JKS.
+KeyStoreNode_Wrong_KeystoreType_Title=Wrong Keystore Type
+KeyStoreRootNode_Error_AlreadyMappedKeystorePath=Keystore in path: {0} is already mapped in the view.
+KeyStoreUtils_RSA_Keys_Expected=RSA keys are expected; use RSAPublicKey and RSAPrivateKey
+KeyStoreUtils_Error_AddEntryToKeyStore=An error has ocurred while attempting to add the entry {0}
+KeyStoreUtils_Error_DeleteKeyStore=Could not delete the keystore file {0}
+KeyStoreUtils_Error_FileAlreadyExists=Keystore file {0} already exists. Choose a new file path.
+KeyStoreUtils_Error_LoadKeyStore=An error has ocurred while attempting to load the keystore file {0}
+KeyStoreUtils_Error_WriteKeyStore=An error has ocurred while attempting to write the keystore file {0}
+KeyStoreUtils_ErrorDeletingAlias=Error deleting alias:
+
+
+UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION = Remove package signatures
+UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE = Package Signature Removal
+UNSIGN_EXTERNAL_PKG_WIZARD_OPERATION = Removing Signature from Package:
+UNSIGN_EXTERNAL_PKG_WIZARD_ERROR = Signatures could not be removed from the following packages
+UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON = Unable to write files
+SelectExistentKeystorePage_CheckboxText_AlsoImportIntoSigningView=Add keystore to Signing and Keys view
+SelectExistentKeystorePage_KeystorePasswordLabel=Keystore Password:
+SelectExistentKeystorePage_WizardPageMessage=Select an existing keystore to use for exporting.
+SelectExistentKeystorePage_WizardPageTitle=Select existing keystore
+SelectExistentKeystoreWizard_BrowseExistentKeystore_PageTitle=Browse existing keystore
+SelectExistentKeystoreWizard_Error_InvalidPassword=Invalid password. Check password again
+SelectExistentKeystoreWizard_Error_KeystoreType=Verify that the keystore type is correct and that the keystore file exists.
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL = Packages folder:
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID = The chosen folder is invalid or does not exist
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY = The chosen source directory is not a directory
+SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION = Sign packages with the chosen key
+SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY = Select a folder containing Android packages.
+SIGN_EXTERNAL_PKG_WIZARD_NO_CERTIFICATE_ERROR = There are no keys available. Obtain a key to sign the selected packages.
+SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES = This folder does not contain any packages
+UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED = Select at least one package
+SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE = Package Signing
+SIGN_EXTERNAL_PKG_WIZARD_OPERATION = Signing Package:
+SIGN_EXTERNAL_PKG_WIZARD_ERROR = The following packages could not be signed
+SIGN_EXTERNAL_PKG_WIZARD_LOAD = Load
+SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM = Filesystem...
+SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE = Workspace...
+SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE = Workspace
+PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON = Select All
+PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON = Deselect All
+SIGN_WIZARD_AREA_SIGN_KEYSTORE_LABEL = Keystore:
+SIGN_WIZARD_AREA_SIGN_KEYS_LABEL = Key:
+SIGN_EXTERNAL_PKG_WIZARD_CHOOSE=Select the directory that contains the APK
+PasswordProvider_DialogTitle=Keystore password
+PasswordProvider_Error_WhileRemovingPassword=Could not open secure Preferences. Failed to remove saved password from keystore {0}.
+PasswordProvider_Error_WhileSaving=Could not open secure Preferences. It will not be possible to save or restore passwords.
+PasswordProvider_MessageLabel=Supply the password for the keystore file: {0}.\n
+PasswordProvider_Key_MessageLabel=When signing a package you must supply the key password.\nEnter the password for the key: {0}.\n
+PasswordProvider_PasswordLabel=Password:
+PasswordProvider_SaveThisPassword=Save password
+RemoveExternalPackageSignaturePage_Package_Tree_Label=Packages to be unsigned:
+RestoreBackupDialog_BackUp_File=Backup File:
+RestoreBackupDialog_BackUpFile_Not_Exist=Selected backup file does not exist.
+RestoreBackupDialog_Browse_Button=Browse...
+RestoreBackupDialog_Default_Message=Choose an archive file and select the keystore files that you want to restore
+RestoreBackupDialog_Destination=Destination:
+RestoreBackupDialog_Dialog_Title=Restore From Backup
+RestoreBackupDialog_Error_Loading_Entries=Unable to load entries from the zip file {0}
+RestoreBackupDialog_Invalid_Dest_Path=Invalid destination path
+RestoreBackupDialog_KeyStores=Keystores
+RestoreBackupDialog_Path_Group=Paths
+RestoreBackupDialog_Select_All=Select All
+RestoreBackupDialog_Select_KeyStore=Select at least one keystore to restore from backup
+RestoreBackupDialog_TitleArea_Message=Restore keystores from a backup
+RestoreBackupHandler_Error_Mapping_Message=Unable to map restored keystores
+RestoreBackupHandler_Error_Mapping_Status=Failed to import restored keystores
+RestoreBackupHandler_Error_Mapping_Title=Error Mapping Nodes
+RestoreBackupHandler_Error_Restoring_Backup_Message=Could not restore keystores from file {0}
+RestoreBackupHandler_Error_Restoring_Backup_Status=Could not extract zip file
+RestoreBackupHandler_Error_Restoring_Backup_Title=Error while restoring backup
+RestoreBackupHandler_RestoreIssue_MissingMetadataFile_WarningDescription=Missing backup metadata file.\nIt wasn't possible to determine the type of keystore(s): {0}.\nThe default type: {1} will be assumed for each.
+RestoreBackupHandler_RestoreIssue_WarningTitle=Restore Issue
+READ_ONLY_TEXT = Read Only
+
+SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE = The device you are trying to use is invalid
+SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG = The path is too long
+SignExternalPackagePage_Package_Tree_Label=Packages to be signed:
+
+#------------------------------------------------------------------------------
+# Tree Decoration
+#------------------------------------------------------------------------------
+CertificatePeriodExpired_Issue=Warning for Android developers: the key will expire on {0}, but Google Play requires it to expire after October 22, 2033.
+CertificatePeriodNotYeatValid_Issue=Key is not yet valid. It is only valid after {0}.
+ChangePasswordKeyHandler_Error_WrongOldKeyPassword=Old password is invalid
+ChangePasswordKeyHandler_Wrong_Key_Password=Could not retrieve the key. Make sure that the old password is correct.
+ChangePasswordKeystoreHandler_Error_ChangingKeystorePassword=Failed to change keystore password
+ChangePasswordKeystoreHandler_Error_WrongOldKeystorePassword=Old password is invalid
+ChangePasswordKeystoreHandler_InvalidOldPassword=The old password is invalid. Could not access keystore {0} to change keystore password.
+ConvertKeyStoreTypeDialog_Alias_Column=Alias
+ConvertKeyStoreTypeDialog_Choose_KeyStore_Msg=Choose a new keystore.
+ConvertKeyStoreTypeDialog_Choose_New_Type_Msg=Choose a new type for the keystore.
+ConvertKeyStoreTypeDialog_CouldNotLoad_Keystores_Error=Could not load mapped keystores
+ConvertKeyStoreTypeDialog_DefaultMessage=Select a keystore along with its new type.
+ConvertKeyStoreTypeDialog_DialogTitle=Change Keystore Type
+ConvertKeyStoreTypeDialog_Entries_Group=Entries
+ConvertKeyStoreTypeDialog_Error_Loading_Keystore=An error has occurred while attempting to load keystore entries.
+ConvertKeyStoreTypeDialog_Incorrect_Entry_Pass=Enter the password for entries with non-verified passwords.
+ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass=Invalid keystore password.
+ConvertKeyStoreTypeDialog_KeyStoreLabel=Keystore:
+ConvertKeyStoreTypeDialog_Load_Button=Load
+ConvertKeyStoreTypeDialog_NewType_Label=New Type:
+ConvertKeyStoreTypeDialog_Original_Type_Label=Original Type:
+ConvertKeyStoreTypeDialog_Password_Column=Password
+ConvertKeyStoreTypeDialog_Password_Label=Password:
+ConvertKeyStoreTypeDialog_Verified_Column=Verified
+ConvertKeyStoreTypeDialog_Verified_Pass_Wrong=Wrong password
+ConvertKeyStoreTypeDialog_Verified_Pass_Yes=Yes
+EntryNode_ErrorGettingCertificateFromEntry=Error getting key from entry: {0}
+EntryNode_NotFoundOrTypeWrong=Not found or type wrong for alias: {0}
+NewKeyBlock_PasswordGroupTitle=Password
+
+#------------------------------------------------------------------------------
+# Change password
+#------------------------------------------------------------------------------
+Passwordinput_EnterOldKeystorePasssword_Message=Change the password for keystore {0}.\nThe keystore password protects they keystore's keys.
+PasswordChanged_Info_Title=Password changed
+PasswordChanged_Info_Message=The password for keystore {0} was successfully changed. +PasswordInput_EnterOldKeyPasssword_Message=The key password protects your key.
+PasswordChanged_KeyInfo_Message=Your key password was successfully changed.
+PasswordChanged_InvalidKeystorePassword=The password for this keystore is invalid.
+ToolsException_GenericError=An unexpected error occurred.
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java new file mode 100644 index 0000000..c519235 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/job/CreateKeyJob.java @@ -0,0 +1,191 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.job;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.composite.NewKeyBlock;
+import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizard;
+
+/**
+ * Creating a key is a time expensive task.
+ * In order to not block the UI while creating the key, a new
+ * job is creating and executed in the background.
+ */
+public class CreateKeyJob extends Job
+{
+ private static final String KEY_PASSWORD_SAVED = "Key password saved";
+
+ private static final String SAVING_KEY_PASSWORD = "Saving key password";
+
+ private static final String KEY_CREATED = "Key created";
+
+ private static final String CREATING_KEY = "Creating key";
+
+ private static final String GETTING_KEY_INFO = "Getting key info";
+
+ private static final int NUMBER_OF_TASKS = 5;
+
+ /*
+ * Key block, used to retrieve information from the create key wizard.
+ */
+ private NewKeyBlock newKeyBlock = null;
+
+ /*
+ * Information to create key
+ */
+ private CertificateDetailsInfo certificateDetailsInfo = null;
+
+ private IKeyStore keystore = null;
+
+ private String keyStorePass;
+
+ public CreateKeyJob(String jobName, NewKeyBlock newKeyBlock,
+ CertificateDetailsInfo certificateDetailsInfo, IKeyStore keystore, String keyStorePass)
+ {
+ super(jobName);
+ this.certificateDetailsInfo = certificateDetailsInfo;
+ this.newKeyBlock = newKeyBlock;
+ this.keystore = keystore;
+ this.keyStorePass = keyStorePass;
+ if (this.keyStorePass == null)
+ {
+ try
+ {
+ this.keyStorePass = keystore.getPasswordProvider().getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor)
+ {
+ SubMonitor subMonitor = SubMonitor.convert(monitor);
+ subMonitor.beginTask(CREATING_KEY, NUMBER_OF_TASKS);
+
+ StudioLogger.debug(GETTING_KEY_INFO);
+ subMonitor.worked(1);
+
+ IKeyStoreEntry entryNode = null;
+ try
+ {
+ StudioLogger.debug(CREATING_KEY);
+ subMonitor.worked(1);
+ String keystorePassword = getKeyStorePassword();
+
+ if (keystorePassword != null)
+ {
+ entryNode =
+ EntryNode.createSelfSignedNode(keystore, keystorePassword,
+ certificateDetailsInfo.getAlias(), certificateDetailsInfo);
+ StudioLogger.debug(KEY_CREATED);
+ subMonitor.worked(1);
+
+ if (newKeyBlock.needToSaveKeyPassword())
+ {
+ StudioLogger.debug(SAVING_KEY_PASSWORD);
+ subMonitor.worked(1);
+ PasswordProvider passwordProvider = new PasswordProvider(keystore.getFile());
+ passwordProvider.savePassword(entryNode.getAlias(),
+ newKeyBlock.getKeyPassword());
+ StudioLogger.debug(KEY_PASSWORD_SAVED);
+ subMonitor.worked(1);
+ }
+ }
+
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.CreateKeyWizard_ErrorCreatingKey_DialogTitle,
+ e.getMessage());
+ StudioLogger.error(CreateKeyWizard.class,
+ CertificateManagerNLS.CreateKeyWizard_ErrorCreatingKey_DialogTitle, e);
+ }
+
+ subMonitor.done();
+ return Status.OK_STATUS;
+ }
+
+ private String getKeyStorePassword() throws KeyStoreManagerException
+ {
+ boolean invalidPass = true;
+ String keystorePassword = this.keyStorePass;
+
+ try
+ {
+ if (keystorePassword != null)
+ {
+ this.keystore.isPasswordValid(keystorePassword);
+ invalidPass = false;
+ }
+ }
+ catch (InvalidPasswordException e1)
+ {
+ invalidPass = true;
+ }
+ while (invalidPass)
+ {
+ try
+ {
+ this.keystore.isPasswordValid(keystorePassword);
+ invalidPass = false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ invalidPass = true;
+ PasswordProvider passwordProvider = new PasswordProvider(this.keystore.getFile());
+ keystorePassword = passwordProvider.getKeyStorePassword(true, false);
+
+ if (keystorePassword == null)
+ {
+ invalidPass = false;
+ }
+ }
+ }
+
+ return keystorePassword;
+ }
+
+ public String getCreatedKeyAlias()
+ {
+ return this.certificateDetailsInfo.getAlias();
+ }
+
+ public IKeyStore getKeyStore()
+ {
+ return this.keystore;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java new file mode 100644 index 0000000..27a565d --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/PackageFile.java @@ -0,0 +1,648 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.CRC32; + +import org.eclipse.core.runtime.IBundleGroup; +import org.eclipse.core.runtime.IBundleGroupProvider; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; + +import com.motorola.studio.android.common.IAndroidConstants; +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorola.studio.android.common.utilities.AndroidUtils; +import com.motorola.studio.android.common.utilities.FileUtil; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; + +/** + * This class is an in-memory package file representation. + */ +public class PackageFile +{ + private static final String COM_MOTOROLA_STUDIO_ANDROID_FEATURE = + "com.motorola.studio.android.feature"; + + /* + * Map of entries contained in this package file + */ + private final Map<String, File> entryMap = new HashMap<String, File>(); + + /* + * Map of temporary entries contained in this package file (it duplicates + * the entries on entryMap) + */ + private final Map<String, File> tempEntryMap = new HashMap<String, File>(); + + /* + * Package manifest + */ + private Manifest manifest; + + private int apiVersion; + + private String targetName; + + private Set<String> rawFiles = new HashSet<String>(); + + /** + * Creates an empty PackageFile. + * + * @param createdBy + * Created-By manifest attribute + */ + public PackageFile(String createdBy) + { + targetName = ""; + apiVersion = -1; + manifest = createManifest(createdBy); + } + + /** + * Creates an empty PackageFile + * + * @param createdBy + * Created-By manifest attribute + */ + public PackageFile(String createdBy, String targetName, int apiVersion) + { + this.targetName = targetName; + this.apiVersion = apiVersion; + manifest = createManifest(createdBy); + } + + /** + * Creates a PackageFile from an existing JarFile + * + * @param jarFile + * the base jar file + * @param apiVersion + * @param targetName + * @throws IOException + * if an I/O error occurs when reading the contents of the base + * jar file + */ + public PackageFile(JarFile jarFile) throws IOException + { + this(jarFile, "", -1); + } + + /** + * Creates a PackageFile from an existing JarFile + * + * @param jarFile + * the base jar file + * @param apiVersion + * @param targetName + * @throws IOException + * if an I/O error occurs when reading the contents of the base + * jar file + */ + public PackageFile(JarFile jarFile, String targetName, int apiVersion) throws IOException + { + manifest = jarFile.getManifest(); + this.targetName = targetName; + this.apiVersion = apiVersion; + String createdBy = generateStudioFingerprint(); + if (manifest == null) + { + manifest = createManifest(createdBy); + } + + // go through all the entries in the base jar file + Enumeration<JarEntry> entryEnum = jarFile.entries(); + + while (entryEnum.hasMoreElements()) + { + JarEntry entry = entryEnum.nextElement(); + if (!entry.getName().equalsIgnoreCase( + CertificateManagerActivator.METAFILES_DIR + + CertificateManagerActivator.JAR_SEPARATOR + + CertificateManagerActivator.MANIFEST_FILE_NAME)) + { + // create a temporary file for this entry + InputStream is = jarFile.getInputStream(entry); + File tempFile = + File.createTempFile(CertificateManagerActivator.TEMP_FILE_PREFIX, null); + tempFile.deleteOnExit(); + + // copy contents from the original file to the temporary file + BufferedInputStream bis = null; + BufferedOutputStream bos = null; + + try + { + bis = new BufferedInputStream(is); + bos = new BufferedOutputStream(new FileOutputStream(tempFile)); + + int c; + while ((c = bis.read()) >= 0) + { + bos.write(c); + } + } + finally + { + if (bis != null) + { + bis.close(); + } + + if (bos != null) + { + bos.close(); + } + } + + // add the temporary file to the package file + setTempEntryFile(entry.getName(), tempFile); + + //check if the entry is not compressed to keep it this way + if (entry.getMethod() == JarEntry.STORED) + { + rawFiles.add(entry.getName()); + } + } + } + } + + private String generateStudioFingerprint() + { + IBundleGroupProvider[] providers = Platform.getBundleGroupProviders(); + List<IBundleGroup> groups = new ArrayList<IBundleGroup>(); + if (providers != null) + { + for (int i = 0; i < providers.length; ++i) + { + IBundleGroup[] bundleGroups = providers[i].getBundleGroups(); + groups.addAll(Arrays.asList(bundleGroups)); + } + } + String version = ""; + for (IBundleGroup group : groups) + { + if (group.getIdentifier().equals(COM_MOTOROLA_STUDIO_ANDROID_FEATURE)) + { + version = group.getVersion(); + break; + } + } + + StringBuilder stringBuilder = + new StringBuilder(CertificateManagerActivator.CREATED_BY_FIELD_VALUE); + stringBuilder.append(" v"); + stringBuilder.append(version); + stringBuilder.append(" - "); + stringBuilder.append(Platform.getOS()); + stringBuilder.append(", "); + stringBuilder.append(Platform.getOSArch()); + stringBuilder.append(". "); + if (targetName.trim().length() > 0) + { + stringBuilder.append("Android target - "); + stringBuilder.append(targetName); + stringBuilder.append(", "); + } + if (apiVersion >= 0) + { + stringBuilder.append("API version - "); + stringBuilder.append(apiVersion); + stringBuilder.append("."); + } + return stringBuilder.toString(); + } + + /** + * Gets the names for all the entries in this package file + * + * @return Set containing the names for all the entries in this package file + */ + public Set<String> getEntryNames() + { + return Collections.unmodifiableSet(entryMap.keySet()); + } + + /** + * Gets the File object for a given entry + * + * @param entryName + * the entry name + * @return the File object corresponding to entryName + */ + public File getEntryFile(String entryName) + { + return entryMap.get(entryName); + } + + /** + * Puts a File object as a named entry in this package file + * + * @param entryName + * the entry name + * @param file + * the File object corresponding to entryName + */ + public void setEntryFile(String entryName, File file) + { + entryMap.put(entryName, file); + } + + /** + * Puts a Temporary File object as a named entry in this package file + * + * @param entryName + * the entry name + * @param tempFile + * the temporary file object corresponding to entryName + */ + public void setTempEntryFile(String entryName, File tempFile) + { + entryMap.put(entryName, tempFile); + tempEntryMap.put(entryName, tempFile); + } + + /** + * Remove the named entry of files map of this package + * + * @param entryName + * the name of entry to be removed + * @throws IOException + */ + public void removeEntryFile(String entryName) throws IOException + { + File entryFile = entryMap.get(entryName); + if (entryFile != null) + { + entryMap.remove(entryName); + if (tempEntryMap.containsKey(entryName)) + { + tempEntryMap.remove(entryName); + deleteFile(entryFile); + } + } + } + + /** + * Remove the meta entry files (files under META-INF folder) + * + * @throws IOException + */ + public void removeMetaEntryFiles() throws IOException + { + String createdBy = + manifest.getMainAttributes().getValue(CertificateManagerActivator.CREATED_BY_FIELD); + Set<String> entries = new HashSet<String>(getEntryNames()); + for (String entry : entries) + { + if (entry.startsWith(CertificateManagerActivator.METAFILES_DIR)) + { + removeEntryFile(entry); + } + } + Manifest cleanManifest = new Manifest(); + cleanManifest.getMainAttributes().putAll(manifest.getMainAttributes()); + if ("".equals(targetName) && (apiVersion <= 0)) //Just removing signatures. + { + cleanManifest.getMainAttributes().putValue( + CertificateManagerActivator.CREATED_BY_FIELD, createdBy); + } + else + { + cleanManifest.getMainAttributes().putValue( + CertificateManagerActivator.CREATED_BY_FIELD, generateStudioFingerprint()); + } + manifest = cleanManifest; + } + + private void writeCompressed(JarOutputStream jarOut, String entryName) throws IOException + { + File file = entryMap.get(entryName); + if ((file.exists()) && (file.isFile())) + { + JarEntry entry = new JarEntry(entryName); + jarOut.putNextEntry(entry); + WritableByteChannel outputChannel = null; + FileChannel readFromFileChannel = null; + FileInputStream inputStream = null; + try + { + outputChannel = Channels.newChannel(jarOut); + inputStream = new FileInputStream(file); + readFromFileChannel = inputStream.getChannel(); + readFromFileChannel.transferTo(0, file.length(), outputChannel); + } + finally + { + try + { + if (jarOut != null) + { + jarOut.closeEntry(); + } + if (readFromFileChannel != null) + { + readFromFileChannel.close(); + } + if (inputStream != null) + { + inputStream.close(); + } + } + catch (IOException e) + { + StudioLogger.error("Could not close stream: ", e.getMessage()); //$NON-NLS-1$ + } + } + } + + } + + private void writeRaw(JarOutputStream jarOut, String entryName) throws IOException + { + FileInputStream inputStream = null; + File file = entryMap.get(entryName); + if ((file.exists()) && (file.isFile())) + { + CRC32 crc = new CRC32(); + JarEntry entry = new JarEntry(entryName); + entry.setMethod(JarEntry.STORED); + entry.setSize(file.length()); + WritableByteChannel outputChannel = null; + FileChannel readFromFileChannel = null; + try + { + outputChannel = Channels.newChannel(jarOut); + inputStream = new FileInputStream(file); + readFromFileChannel = inputStream.getChannel(); + + ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); + crc.reset(); + while (readFromFileChannel.read(buffer) > 0) + { + buffer.flip(); + byte[] byteArray = new byte[buffer.limit()]; + buffer.get(byteArray, 0, buffer.limit()); + crc.update(byteArray); + buffer.clear(); + } + entry.setCrc(crc.getValue()); + jarOut.putNextEntry(entry); + readFromFileChannel.transferTo(0, file.length(), outputChannel); + } + finally + { + if (inputStream != null) + { + inputStream.close(); + } + if (readFromFileChannel != null) + { + readFromFileChannel.close(); + } + jarOut.closeEntry(); + } + } + } + + /** + * Writes this package file to an output stream + * + * @param outputStream + * the stream to write the package to + * @throws IOException + * if an I/O error occurs when writing the package contents to + * the output stream + */ + public void write(OutputStream outputStream) throws IOException + { + // create a jar output stream + JarOutputStream jarOut = null; + + try + { + jarOut = new JarOutputStream(outputStream, manifest); + + // for each entry in the package file + for (String jarEntryName : entryMap.keySet()) + { + if (jarEntryName.contains("raw/") || rawFiles.contains(jarEntryName)) + { + writeRaw(jarOut, jarEntryName); + } + else + { + writeCompressed(jarOut, jarEntryName); + } + } + } + finally + { + if (jarOut != null) + { + try + { + jarOut.finish(); + jarOut.close(); + } + catch (IOException e) + { + StudioLogger.error("Could not close stream while writing jar file. " + + e.getMessage()); + } + } + } + } + + /** + * Calculate the package total size returns long + */ + public long getTotalSize() + { + long totalSize = 0; + + for (String jarEntryName : entryMap.keySet()) + { + File file = entryMap.get(jarEntryName); + if ((file.exists()) && (file.isFile())) + { + totalSize += file.length(); + } + } + + return totalSize; + } + + /** + * Gets the package manifest + * + * @return the package manifest + */ + public Manifest getManifest() + { + return manifest; + } + + /** + * Remove the temporary entry files + * + * @throws IOException + */ + public void removeTemporaryEntryFiles() throws IOException + { + Set<String> tempEntries = + new HashSet<String>(Collections.unmodifiableSet(tempEntryMap.keySet())); + for (String tempEntry : tempEntries) + { + removeEntryFile(tempEntry); + } + } + + /* + * Delete a single file from the filesystem. + * + * @param fileToDelete + * A <code>File</code> object representing the file to be + * deleted. + * @throws IOException + * if any problem occurs deleting the file. + */ + private void deleteFile(File fileToDelete) throws IOException + { + if ((fileToDelete != null) && fileToDelete.exists() && fileToDelete.isFile() + && fileToDelete.canWrite()) + { + fileToDelete.delete(); + } + else + { + String errorMessage = ""; + if (fileToDelete == null) + { + errorMessage = "Null pointer for file to delete."; + } + else + { + if (!fileToDelete.exists()) + { + errorMessage = "The file " + fileToDelete.getName() + " does not exist."; + } + else + { + if (!fileToDelete.isFile()) + { + errorMessage = fileToDelete.getName() + " is not a file."; + } + else + { + if (!fileToDelete.canWrite()) + { + errorMessage = "Cannot write to " + fileToDelete.getName(); + } + } + } + + } + throw new IOException("Cannot delete file: " + errorMessage); + } + } + + /** + * Create a new Manifest with the basic values and the created by string + * @param createdBy who is creating this manifest + * @return a new Manifest with basic values and desired created by string + */ + public Manifest createManifest(String createdBy) + { + Manifest newManifest = new Manifest(); + Attributes mainAttributes = newManifest.getMainAttributes(); + mainAttributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), + CertificateManagerActivator.MANIFEST_VERSION); + mainAttributes.putValue(CertificateManagerActivator.CREATED_BY_FIELD, createdBy); + return newManifest; + } + + /** + * Execute the zipalign for a certain apk + * @param apk + */ + public static void zipAlign(File apk) + { + // String zipAlign = SdkUtils.getSdkToolsPath(); + String zipAlign = + AndroidUtils.getSDKPathByPreference() + Path.SEPARATOR + IAndroidConstants.FD_TOOLS; + try + { + File tempFile = File.createTempFile("_tozipalign", ".apk"); + FileUtil.copyFile(apk, tempFile); + + if (!zipAlign.endsWith(File.separator)) + { + zipAlign += File.separator; + } + zipAlign += Platform.getOS().equals(Platform.OS_WIN32) ? "zipalign.exe" : "zipalign"; + + String[] command = new String[] + { + zipAlign, "-f", "-v", "4", tempFile.getAbsolutePath(), apk.getAbsolutePath() + }; + StringBuilder commandLine = new StringBuilder(); + for (String commandPart : command) + { + commandLine.append(commandPart); + commandLine.append(" "); + } + + StudioLogger.info(PackageFile.class, "Zipaligning package: " + commandLine.toString()); + Runtime.getRuntime().exec(command); + } + catch (IOException e) + { + StudioLogger.error(PackageFile.class, "Error while zipaligning package", e); + } + catch (Exception e) + { + StudioLogger.error(PackageFile.class, + "Zipalign application cannot be executed - insuficient permissions", e); + } + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java new file mode 100644 index 0000000..cb8e4df --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ISignConstants.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +public interface ISignConstants +{ + /** + * md5 algorithm + */ + public final String MD5 = "MD5"; + + /** + * rsa algorithm + */ + public final String RSA = "RSA"; + + /** + * dsa algorithm + */ + public final String DSA = "DSA"; + + /** + * sha1 algorithm + */ + public final String SHA1 = "SHA1"; + + /** + * algorithm connector + */ + public final String ALGORITHM_CONNECTOR = "with"; + + /** + * Signature file name extension + */ + public final String SIGNATURE_FILE_NAME_EXTENSION = ".SF"; + + /** + * Signature Version + */ + public final String SIGNATURE_VERSION_KEY = "Signature-Version"; + + public final String SIGNATURE_VERSION_VALUE = "1.0"; + + /** + * Digest algorithm entry in manifest + */ + public final String SHA1_DIGEST = "SHA1-Digest"; + + /** + * sha1-digest-manifest signature entry + */ + public final String SHA1_DIGEST_MANIFEST = "SHA1-Digest-Manifest"; + + /** + * manifest main attributes signature entry + */ + public final String SHA1_DIGEST_MANIFEST_MAIN = "SHA1-Digest-Manifest-Main-Attributes"; + + /** + * Name of the signature files (.SF and .RSA) + */ + public final String SIGNATURE_FILE_NAME = "CERT"; +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java new file mode 100644 index 0000000..9ebcee6 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestDigester.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import com.motorola.studio.android.common.log.StudioLogger; + +/** + * This class is a Manifest digester. + * It generates digested hashes for each entry in the manifest file. + */ +public class ManifestDigester +{ + private final Manifest manifest; + + private HashMap<String, ManifestEntry> entries = null; + + /** + * Create a new manifest digester with the given manifest + * @param manifest + */ + public ManifestDigester(final Manifest manifest) + { + this.manifest = manifest; + initialize(); + } + + /** + * Initialize the digester creating internal entries for each manifest entry + */ + private void initialize() + { + Map<String, Attributes> manifestEntries = manifest.getEntries(); + + // initialize internal entries list + entries = new HashMap<String, ManifestEntry>(manifestEntries.size()); + for (String entryName : manifestEntries.keySet()) + { + entries.put(entryName, new ManifestEntry(entryName, manifestEntries.get(entryName))); + } + } + + /** + * Get this Manifest file digested + * @throws IOException if some error occurs during entries encoding + */ + public String getDigestedString() throws IOException + { + StringBuilder builder = new StringBuilder(); + for (ManifestEntry entry : entries.values()) + { + builder.append(entry.toDigestedManifestEntry()); + builder.append(ManifestEntry.MANIFEST_NEW_LINE); + } + return builder.toString(); + } + + public HashMap<String, ManifestEntry> getEntries() + { + return entries; + } + + /** + * Computes the digest for the main manifest attributes + * + * @return the digest of the main manifest attributes or null otherwise + * @throws SignException + * if a processing error occurs when computing the digest + */ + public byte[] getDigestedManifestMainAttributes() throws SignException + { + // create an auxiliary manifest that contain only the main attributes + // of the original manifest + Manifest auxManifest = new Manifest(); + byte[] result; + Attributes auxMainAttributes = auxManifest.getMainAttributes(); + Attributes mainAttributes = manifest.getMainAttributes(); + for (Object attributeKey : mainAttributes.keySet()) + { + String name = attributeKey.toString(); + String value = mainAttributes.getValue(name); + auxMainAttributes.putValue(name, value); + } + + result = getDigestedManifest(auxManifest); + + StudioLogger.info(SignatureFile.class, "Created digest for main manifest attributes"); + + return result; + } + + /** + * Get this Manifest digested + * @return + * @throws SignException + */ + public byte[] getDigestedManifest() throws SignException + { + return getDigestedManifest(manifest); + } + + /** + * Computes the digest for the manifest + * + * @param manifest + * the manifest to be digested + * @return the digest of the entire manifest or null otherwise + * @throws SignException + * if a processing error occurs when computing the digest + */ + public static byte[] getDigestedManifest(Manifest manifest) throws SignException + { + byte[] digestedManifestBytes = null; + ByteArrayOutputStream baos = null; + try + { + MessageDigest messageDigest = MessageDigest.getInstance(ISignConstants.SHA1); + baos = new ByteArrayOutputStream(); + manifest.write(baos); + + messageDigest.reset(); + digestedManifestBytes = messageDigest.digest(baos.toByteArray()); + } + catch (IOException e) + { + StudioLogger.error(SignatureFile.class, + "I/O error encoding manifest digest: " + e.getMessage()); + + throw new SignException("I/O error encoding manifest digest", e); + } + catch (NoSuchAlgorithmException e) + { + StudioLogger.error(SignatureFile.class, "Error getting message digester"); + + throw new SignException("Could digest the manifest"); + } + finally + { + try + { + if (baos != null) + { + baos.close(); + } + } + catch (IOException e) + { + //do nothing + } + } + + if (digestedManifestBytes == null) + { + StudioLogger.error(SignatureFile.class, "Error encoding manifest digest"); + + throw new SignException("Could not encode manifest digest"); + } + + StudioLogger.info(SignatureFile.class, "Created manifest digest"); + + return digestedManifestBytes; + } +}
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java new file mode 100644 index 0000000..b7223ec --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/ManifestEntry.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Iterator; +import java.util.jar.Attributes; + +import org.bouncycastle.util.encoders.Base64Encoder; + +import com.motorola.studio.android.common.log.StudioLogger; + +/** + * A Class representing a Manifest Entry. + */ +public class ManifestEntry +{ + /** + * New line string according Jar specification + */ + public static final String MANIFEST_NEW_LINE = "\r\n"; + + public static final String ENTRY_NAME_ATTRIBUTE = "Name: "; + + public static final String UTF8_CHARSET = "UTF-8"; + + /** + * Safe line size limit according Jar Specification + */ + public static final int SAFE_LIMIT = 72; + + private final String name; + + private final Attributes attributes; + + /** + * Create a new ManifestEntry with the desired name and attributes + * @param name + * @param attr + */ + public ManifestEntry(String name, Attributes attr) + { + this.name = name; + this.attributes = attr; + } + + /** + * Get the manifest as it will be written in the Manifest file + * @return a byte array representing the manifest entry + */ + public byte[] toManifestEntryBytes() + { + byte[] result = null; + DataOutputStream dataOut = null; + ByteArrayOutputStream stream = null; + try + { + stream = new ByteArrayOutputStream(); + dataOut = new DataOutputStream(stream); + String nameField = wrap72bytes(ENTRY_NAME_ATTRIBUTE + name); + dataOut.writeBytes(nameField); + dataOut.writeBytes(MANIFEST_NEW_LINE); + dataOut.writeBytes(getAttributesString()); + dataOut.writeBytes(MANIFEST_NEW_LINE); + dataOut.writeBytes(MANIFEST_NEW_LINE); + result = stream.toString().getBytes(UTF8_CHARSET); + + } + catch (IOException e) + { + StudioLogger.error(ManifestEntry.class, "Error getting manifest like bytes"); + } + finally + { + try + { + if (dataOut != null) + { + dataOut.close(); + } + if (stream != null) + { + stream.close(); + } + } + catch (IOException e) + { + StudioLogger + .error("Could not close stream while writing manifest" + e.getMessage()); + } + } + + return result; + } + + /** + * Digest the entire entry + * @return a byte array with the SHA-1 sum of this entry + */ + public byte[] digest() + { + byte[] digested = null; + try + { + MessageDigest digester = MessageDigest.getInstance("SHA-1"); + digester.reset(); + digester.update(toManifestEntryBytes()); + digested = digester.digest(); + } + catch (NoSuchAlgorithmException e) + { + StudioLogger.error(ManifestEntry.class, "Error digesting manifest bytes"); + } + return digested; + } + + /** + * Get this Entry attributes as it will be written in the Manifest file + * @return + */ + private String getAttributesString() + { + StringBuilder builder = new StringBuilder(); + Iterator<Object> it = attributes.keySet().iterator(); + while (it.hasNext()) + { + Object next = it.next(); + String line = wrap72bytes(next + ": " + attributes.get(next)); + if (it.hasNext()) + { + line += MANIFEST_NEW_LINE; + } + builder.append(line); + } + return builder.toString(); + } + + /** + * Wrap a string into another string with at most 72 bytes per line + * According Jar spec, each line must have at most 72 bytes + * @param line + * @return the wrapped string + */ + public static String wrap72bytes(String line) + { + String returnString = line; + + if (line.length() > SAFE_LIMIT) + { + int maximumLength = SAFE_LIMIT - MANIFEST_NEW_LINE.length(); + StringBuilder wrapped = new StringBuilder(); + int index = maximumLength; + String first = line.substring(0, index); //get first SAFE_LIMIT - MANIFEST_NEW_LINE.length() bytes + first += MANIFEST_NEW_LINE; + wrapped.append(first); + while (index < line.length()) + { + String medium = " "; + if ((index + maximumLength) < line.length()) + { + medium += line.substring(index, index + maximumLength); //get the maximum length minus the blank space size + } + else + { + medium += line.substring(index); + } + wrapped.append(medium); + index += maximumLength; + } + returnString = wrapped.toString(); + } + + return returnString; + } + + /** + * Get this entry name + * @return this entry name + */ + public String getName() + { + return name; + } + + /** + * Get this entry ready to be written in the Signature File + * @return this entry ready to be written in the Signature File + * @throws IOException if some error occurs during encoding + */ + public String toDigestedManifestEntry() throws IOException + { + Base64Encoder encoder = new Base64Encoder(); + StringBuilder builder = new StringBuilder(); + ByteArrayOutputStream output = null; + + try + { + output = new ByteArrayOutputStream(); + + builder.append(wrap72bytes(ENTRY_NAME_ATTRIBUTE + name)); + builder.append(MANIFEST_NEW_LINE); + builder.append(ISignConstants.SHA1_DIGEST + ": "); + + byte[] digest = digest(); + encoder.encode(digest, 0, digest.length, output); + + builder.append(output.toString()); + builder.append(MANIFEST_NEW_LINE); + } + finally + { + if (output != null) + { + try + { + output.close(); + } + catch (IOException e) + { + StudioLogger.error("Could not close stream: " + e.getMessage()); + } + } + } + return builder.toString(); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java new file mode 100644 index 0000000..32a5b3f --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/PackageFileSigner.java @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.util.jar.Attributes; + +import org.bouncycastle.util.encoders.Base64Encoder; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.packaging.PackageFile; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry; + +/** + * Utility class used to sign package files. + */ +public class PackageFileSigner +{ + public static final String MOTODEV_STUDIO = "MOTODEV Studio"; + + /** + * Signs a package file + * + * @param packageFile + * the package file to sign + * @param certificateAlias + * the signing certificate alias + * @param createdBy + * Created-By manifest attribute + * @throws SignException + * if a processing error occurs during the signing process + * @throws UnrecoverableKeyException + */ + public static void signPackage(PackageFile packageFile, IKeyStoreEntry keystoreEntry, + String keyEntryPassword, String createdBy) throws SignException, + UnrecoverableKeyException + { + + try + { + Base64Encoder encoder = new Base64Encoder(); + MessageDigest messageDigest = MessageDigest.getInstance(ISignConstants.SHA1); + + addFilesDigestsToManifest(packageFile, encoder, messageDigest); + + addSignatureFiles(packageFile, keystoreEntry, keyEntryPassword, encoder, createdBy); + } + catch (UnrecoverableKeyException e) + { + throw e; + } + catch (Exception e) + { + StudioLogger.error(PackageFileSigner.class, "Error signing package", e); + throw new SignException(e.getMessage(), e); + } + + } + + /** + * Remove package signature files + * + * @param packageFile + * @throws IOException + */ + public static void removePackageSignature(PackageFile packageFile) throws IOException + { + packageFile.removeMetaEntryFiles(); + } + + /** + * Generates the digests for all the files in the package and puts them in + * the manifest + * + * @param packageFile + * the package file being signed + * @param encoder + * the BASE64 encoder + * @param messageDigest + * the message digest + * @throws IOException + * if an I/O error occurs when reading the files contained in + * the package + */ + private static void addFilesDigestsToManifest(PackageFile packageFile, Base64Encoder encoder, + MessageDigest messageDigest) throws IOException + { + InputStream fileInputStream = null; + ReadableByteChannel rc = null; + ByteArrayOutputStream encodedStream = null; + + // for each entry in the package file + for (String entryName : packageFile.getEntryNames()) + { + File file = packageFile.getEntryFile(entryName); + if (file.isFile()) + { + try + { + // read the file contents + fileInputStream = new FileInputStream(file); + rc = Channels.newChannel(fileInputStream); + ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length()); + rc.read(byteBuffer); + + // compute the digest + messageDigest.reset(); + byte[] digestedArray = messageDigest.digest(byteBuffer.array()); + + encodedStream = new ByteArrayOutputStream(); + encoder.encode(digestedArray, 0, digestedArray.length, encodedStream); + String digestedMessage = encodedStream.toString(); + + // put the digest in the manifest file + Attributes jarEntryAttributes = new Attributes(); + jarEntryAttributes.putValue(ISignConstants.SHA1_DIGEST, digestedMessage); + packageFile.getManifest().getEntries().put(entryName, jarEntryAttributes); + } + finally + { + try + { + if (encodedStream != null) + { + encodedStream.close(); + } + if (rc != null) + { + rc.close(); + } + if (fileInputStream != null) + { + fileInputStream.close(); + } + } + catch (IOException e) + { + StudioLogger.error("Could not close stream while signing package. " + + e.getMessage()); + } + } + } + } + } + + /** + * Adds the signature file and the signature block file to the package + * + * @param packageFile + * the package file being signed + * @param certificateAlias + * the signing certificate alias + * @param encoder + * the BASE64 encoder + * @param messageDigest + * the message digest + * @param createdBy + * Created-By manifest attribute + * @throws SignException + * if a processing error occurs during the signing process + * @throws IOException + * if an I/O error occurs during the signing process + * @throws NoSuchAlgorithmException + * @throws KeyStoreManagerException + * @throws KeyStoreException + * @throws UnrecoverableKeyException + */ + private static void addSignatureFiles(PackageFile packageFile, IKeyStoreEntry keystoreEntry, + String keyEntryPassword, Base64Encoder encoder, String createdBy) throws IOException, + SignException, UnrecoverableKeyException, KeyStoreException, KeyStoreManagerException, + NoSuchAlgorithmException + { + // signature file + SignatureFile signatureFile = + new SignatureFile(packageFile, keystoreEntry.getAlias(), encoder, createdBy); + + File sigFile = File.createTempFile(CertificateManagerActivator.TEMP_FILE_PREFIX, null); + FileOutputStream sigFileOutStream = null; + + try + { + sigFileOutStream = new FileOutputStream(sigFile); + signatureFile.write(sigFileOutStream); + } + finally + { + if (sigFileOutStream != null) + { + try + { + sigFileOutStream.close(); + } + catch (IOException e) + { + StudioLogger + .error("Could not close stream while adding signature files to package. " + + e.getMessage()); + } + } + } + + packageFile.setTempEntryFile(signatureFile.toString(), sigFile); + + // signature block file + SignatureBlockFile signatureBlockFile = + new SignatureBlockFile(signatureFile, keystoreEntry, keyEntryPassword); + + File sigBlockFile = File.createTempFile(CertificateManagerActivator.TEMP_FILE_PREFIX, null); + FileOutputStream sigBlockFileOutStream = null; + + try + { + sigBlockFileOutStream = new FileOutputStream(sigBlockFile); + signatureBlockFile.write(sigBlockFileOutStream); + } + finally + { + if (sigBlockFileOutStream != null) + { + try + { + sigBlockFileOutStream.close(); + } + catch (IOException e) + { + StudioLogger + .error("Could not close stream while adding signature files to package. " + + e.getMessage()); + } + } + } + + packageFile.setTempEntryFile(signatureBlockFile.toString(), sigBlockFile); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java new file mode 100644 index 0000000..901a420 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignException.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +/** + * Signing exception + */ +@SuppressWarnings("serial") +public class SignException extends Exception +{ + /** + * Creates a SignException with a detail message + * + * @param message the detail message + */ + public SignException(String message) + { + super(message); + } + + /** + * Creates a SignException with a detail message and a cause + * + * @param message the detail message + * @param cause the cause + */ + public SignException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java new file mode 100644 index 0000000..f8fdcad --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureBlockFile.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import sun.security.pkcs.ContentInfo; +import sun.security.pkcs.PKCS7; +import sun.security.pkcs.SignerInfo; +import sun.security.x509.AlgorithmId; +import sun.security.x509.X500Name; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry; + +/** + * This class implements the signature block file from jar mechanism used in packaging + */ +public class SignatureBlockFile +{ + + /** + * the signature file + */ + private SignatureFile signatureFile; + + /** + * A certificate from keystore + */ + private IKeyStoreEntry keystoreEntry; + + /** + * The password of the certificate. + */ + private String keyEntryPassword; + + /** + * Default Constructor + * + * @param signatureFile the signature file + * @param alias the certificate alias + */ + public SignatureBlockFile(SignatureFile signatureFile, IKeyStoreEntry keystoreEntry, + String keyEntryPassword) + { + this.keyEntryPassword = keyEntryPassword; + this.keystoreEntry = keystoreEntry; + this.signatureFile = signatureFile; + } + + /** + * To string method override + * + * @return the signature block file name with relative path from root. Frequently META-INF/alias.RSA or .DSA + */ + @Override + public String toString() + { + String result = new String(); + try + { + result = + new StringBuilder(CertificateManagerActivator.METAFILES_DIR) + .append(CertificateManagerActivator.JAR_SEPARATOR) + .append(ISignConstants.SIGNATURE_FILE_NAME).append(".") + .append(getBlockAlgorithm()).toString(); + } + catch (UnrecoverableKeyException e) + { + StudioLogger.error("Could not generate signature block file name."); + } + catch (KeyStoreException e) + { + StudioLogger.error("Could not generate signature block file name."); + } + catch (NoSuchAlgorithmException e) + { + StudioLogger.error("Could not generate signature block file name."); + } + catch (KeyStoreManagerException e) + { + StudioLogger.error("Could not generate signature block file name."); + } + + return result; + } + + /** + * Gets the block file algorithm + * + * @return the signature block file algorithm to be used + * @throws KeyStoreManagerException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws UnrecoverableKeyException + * @throws + */ + private String getBlockAlgorithm() throws UnrecoverableKeyException, KeyStoreException, + NoSuchAlgorithmException, KeyStoreManagerException + { + return keystoreEntry.getKey(this.keyEntryPassword).getAlgorithm(); + } + + /** + * Writes this file to an output stream + * + * @param outputStream the output stream to write the file + * @throws IOException if an I/O error occurs during the signing process + * @throws SignException if a processing error occurs during the signing process + * @throws KeyStoreManagerException + * @throws KeyStoreException + * @throws UnrecoverableKeyException + * @throws NoSuchAlgorithmException + */ + public void write(OutputStream outputStream) throws IOException, SignException, + UnrecoverableKeyException, KeyStoreException, KeyStoreManagerException, + NoSuchAlgorithmException + { + // get certificate from entry + X509Certificate[] certChain = + { + keystoreEntry.getX509Certificate() + }; + if (certChain.length > 0) + { + //get some info from certificate as issuer, serial and algorithm + X500Principal issuer = certChain[0].getIssuerX500Principal(); + String serial = certChain[0].getSerialNumber().toString(); + String blockalgorithm = getBlockAlgorithm(); + + String digestAlgotithm = null; + // determine the algorithm to be used to cipher the block file + if (blockalgorithm.equalsIgnoreCase(ISignConstants.DSA)) + { + digestAlgotithm = ISignConstants.SHA1; + } + else if (blockalgorithm.equalsIgnoreCase(ISignConstants.RSA)) + { + digestAlgotithm = ISignConstants.MD5; + } + else + { + StudioLogger.error(SignatureBlockFile.class, + "Signing block algorithm not supported. Key algorithm must be DSA or RSA"); + + throw new SignException("Signing block algorithm not supported"); + } + + String signatureAlgorithm = + digestAlgotithm + ISignConstants.ALGORITHM_CONNECTOR + blockalgorithm; + + AlgorithmId digestAlg; + try + { + digestAlg = AlgorithmId.get(digestAlgotithm); + AlgorithmId privateKeyAlg = AlgorithmId.get(blockalgorithm); + // write the certificate with signature file and cipher it + Signature sig = Signature.getInstance(signatureAlgorithm); + sig.initSign(keystoreEntry.getPrivateKey(this.keyEntryPassword)); + + PKCS7 block = null; + ByteArrayOutputStream baos = null; + ByteArrayOutputStream signature = null; + + try + { + baos = new ByteArrayOutputStream(); + signatureFile.write(baos); + + ContentInfo contentInfo = new ContentInfo(ContentInfo.DATA_OID, null); + sig.update(baos.toByteArray()); + + signature = new ByteArrayOutputStream(); + signature.write(sig.sign()); + + SignerInfo si = + new SignerInfo(new X500Name(issuer.getName()), new BigInteger(serial), + digestAlg, privateKeyAlg, signature.toByteArray()); + + AlgorithmId[] algs = + { + digestAlg + }; + SignerInfo[] infos = + { + si + }; + + block = new PKCS7(algs, contentInfo, certChain, infos); + } + catch (IOException e) + { + StudioLogger.error(SignatureBlockFile.class, + "I/O error creating signature block file: " + e.getMessage()); + + throw new SignException("I/O error creating signature block file", e); + } + finally + { + if (baos != null) + { + baos.close(); + } + if (signature != null) + { + signature.close(); + } + } + + // I/O exceptions below are thrown unmodified + block.encodeSignedData(outputStream); + } + catch (NoSuchAlgorithmException nsae) + { + StudioLogger.error(SignatureBlockFile.class, "Signing algorithm not supported: " + + nsae.getMessage()); + + throw new SignException("Signing algorithm not supported", nsae); + } + catch (InvalidKeyException ike) + { + StudioLogger.error(SignatureBlockFile.class, + "Invalid key when creating signature block file: " + ike.getMessage()); + + throw new SignException("Invalid key when creating signature block file", ike); + } + catch (SignatureException se) + { + StudioLogger.error(SignatureBlockFile.class, + "Signature error when creating signature block file: " + se.getMessage()); + + throw new SignException("Signature error creating signature block file", se); + } + } + StudioLogger.info(SignatureBlockFile.class, "Created signature block file"); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java new file mode 100644 index 0000000..669cf70 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/packaging/sign/SignatureFile.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.packaging.sign; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import org.bouncycastle.util.encoders.Base64Encoder; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.packaging.PackageFile; + +/** + * This class implements the package signature file, that follows the jar + * signing process. + */ +public class SignatureFile +{ + /** + * The package file + */ + private final PackageFile packageFile; + + /** + * The base encoder + */ + private Base64Encoder encoder = new Base64Encoder(); + + /** + * Manifest Created-By attribute + */ + private final String createdBy; + + /** + * Default Constructor + * + * @param packageFile + * the signed package file to be signed + * @param alias + * the certificate alias + * @param encoder + * the BASE64 encoder + * @param createdBy + * Created-By manifest attribute + */ + public SignatureFile(PackageFile packageFile, String alias, Base64Encoder encoder, + String createdBy) + { + this.packageFile = packageFile; + this.encoder = encoder; + this.createdBy = createdBy; + } + + /** + * Return the filename with relative path from root (normally + * META-INF/alias.SF). + */ + @Override + public String toString() + { + return CertificateManagerActivator.METAFILES_DIR + + CertificateManagerActivator.JAR_SEPARATOR + ISignConstants.SIGNATURE_FILE_NAME + + ISignConstants.SIGNATURE_FILE_NAME_EXTENSION; + + } + + /** + * Writes this file to an output stream. + * + * @param outputStream + * the stream to write this file + * @throws IOException + * if an I/O error occurs during the signing process + * @throws SignException + * if a processing error occurs during the signing process + */ + public void write(OutputStream outputStream) throws IOException, SignException + { + // the manifest file + Manifest manifestFile = this.packageFile.getManifest(); + + // the manifest digester + ManifestDigester manifestDigester = new ManifestDigester(manifestFile); + + // the signature file to be constructed + Manifest signatureFile = new Manifest(); + + // the manifest digested main attributes + byte[] digestedMainAttributes = manifestDigester.getDigestedManifestMainAttributes(); + + // the digest of entire manifest + byte[] digestedManifest = manifestDigester.getDigestedManifest(); + + // put the required main attributes to a valid signature file + // (Version, CreatedBy, Main Attrib digest, Manifest digest) + Attributes signatureFileMainAtt = signatureFile.getMainAttributes(); + signatureFileMainAtt.putValue(ISignConstants.SIGNATURE_VERSION_KEY, + ISignConstants.SIGNATURE_VERSION_VALUE); + signatureFileMainAtt.putValue(CertificateManagerActivator.CREATED_BY_FIELD, this.createdBy); + + ByteArrayOutputStream stream = null; + + try + { + stream = new ByteArrayOutputStream(); + encoder.encode(digestedMainAttributes, 0, digestedMainAttributes.length, stream); + String encodedMainAttributesDigest = stream.toString(); + + stream.reset(); + encoder.encode(digestedManifest, 0, digestedManifest.length, stream); + String encodedManifestDigest = stream.toString(); + + signatureFileMainAtt.putValue(ISignConstants.SHA1_DIGEST_MANIFEST_MAIN, + encodedMainAttributesDigest); + signatureFileMainAtt.putValue(ISignConstants.SHA1_DIGEST_MANIFEST, + encodedManifestDigest); + } + finally + { + if (stream != null) + { + try + { + stream.close(); + } + catch (IOException e) + { + StudioLogger.error("Could not close stream writing signature file. " + + e.getMessage()); + } + } + } + + // calculate the digest from each entry of manifest + ByteArrayOutputStream baos = null; + try + { + baos = new ByteArrayOutputStream(); + manifestFile.write(baos); + + Map<String, Attributes> manifestEntries = manifestFile.getEntries(); + Map<String, Attributes> signatureFileEntries = signatureFile.getEntries(); + HashMap<String, ManifestEntry> entries = manifestDigester.getEntries(); + + for (String manifestEntryKey : manifestEntries.keySet()) + { + ManifestEntry signatureFileEntry = entries.get(manifestEntryKey); + + byte[] digestedArray = signatureFileEntry.digest(); + + ByteArrayOutputStream encodedStream = null; + + try + { + encodedStream = new ByteArrayOutputStream(); + this.encoder.encode(digestedArray, 0, digestedArray.length, encodedStream); + + String digestedValue = encodedStream.toString(); + + Attributes signatureFileAtt = new Attributes(); + signatureFileAtt.putValue(ISignConstants.SHA1_DIGEST, digestedValue); + signatureFileEntries.put(manifestEntryKey, signatureFileAtt); + } + finally + { + try + { + if (encodedStream != null) + { + encodedStream.close(); + } + } + catch (IOException e) + { + StudioLogger.error("Could not close stream: " + e.getMessage()); + } + } + } + } + catch (IOException e) + { + StudioLogger.error(SignatureFile.class, + "I/O error digesting manifest entries: " + e.getMessage()); + + throw new SignException("I/O error digesting manifest entries", e); + } + finally + { + try + { + if (baos != null) + { + baos.close(); + } + } + catch (IOException e) + { + StudioLogger.error("Could not close stream: " + e.getMessage()); + } + } + + // I/O exceptions below are thrown unmodified + signatureFile.write(outputStream); + + StudioLogger.info(SignatureFile.class, "Signature file was written"); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java new file mode 100644 index 0000000..033dc01 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/property/tester/TreeNodeTester.java @@ -0,0 +1,50 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.property.tester;
+
+import org.eclipse.core.expressions.PropertyTester;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+/**
+ * Property testers are used via extension point to test object's state properties.
+ * This tester checks {@link ITreeNode} properties.
+ * */
+public class TreeNodeTester extends PropertyTester
+{
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.expressions.IPropertyTester#test(Object,String,Object[],Object)
+ */
+ @Override
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue)
+ {
+ boolean result = false;
+
+ if (receiver instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) receiver;
+ result =
+ treeNode.testAttribute(receiver,
+ ITreeNode.PROP_NAMESPACE.concat("." + property),
+ expectedValue.toString());
+ }
+
+ return result;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java new file mode 100644 index 0000000..ad2c4d2 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/PopupMenuActionDelegate.java @@ -0,0 +1,224 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.action;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.command.BackupHandler;
+import com.motorolamobility.studio.android.certmanager.command.CertificatePropertiesHandler;
+import com.motorolamobility.studio.android.certmanager.command.ChangeKeyStoreTypeHandler;
+import com.motorolamobility.studio.android.certmanager.command.ChangePasswordKeyHandler;
+import com.motorolamobility.studio.android.certmanager.command.ChangePasswordKeystoreHandler;
+import com.motorolamobility.studio.android.certmanager.command.CreateKeyHandler;
+import com.motorolamobility.studio.android.certmanager.command.DeleteKeyHandler;
+import com.motorolamobility.studio.android.certmanager.command.DeleteKeystoreHandler;
+import com.motorolamobility.studio.android.certmanager.command.ImportKeyStoreEntriesHandler;
+import com.motorolamobility.studio.android.certmanager.command.RefreshHandler;
+import com.motorolamobility.studio.android.certmanager.command.SignExternalPackagesHandler;
+
+public class PopupMenuActionDelegate implements IObjectActionDelegate
+{
+
+ /**
+ * Enum type for ActionHandlers. If you need to add a new ActionHandler, just include
+ * a new type to this enum with the action id that you defined on your action extension point
+ */
+ enum ActionHandlers
+ {
+ SIGN_PACKAGE("com.motorolamobility.studio.android.certmanager.core.ui.action.addSignature") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new SignExternalPackagesHandler();
+ }
+ },
+ BACKUP_KEYSTORE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.backupKeystore") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ //this handler will delegate the operation to another action that, in turn,
+ //will retrieve the current selection
+ //therefore, the parameter treeNode is not used here.
+ return new BackupHandler();
+ }
+
+ },
+ DELETE_KEYSTORE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.deleteKeystore") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new DeleteKeystoreHandler();
+ }
+
+ },
+ PROPERTIES_KEYSTORE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.certificateProperties") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new CertificatePropertiesHandler();
+ }
+
+ },
+ CHANGE_KEYSTORE_PASSWORD(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.changeKeystorePassword") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ChangePasswordKeystoreHandler();
+ }
+
+ },
+ CHANGE_KEY_PASSWORD(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.changeKeyPassword") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ChangePasswordKeyHandler();
+ }
+
+ },
+ CREATE_KEY("com.motorolamobility.studio.android.certmanager.core.ui.action.createKey") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new CreateKeyHandler();
+ }
+
+ },
+ DELETE_KEY("com.motorolamobility.studio.android.certmanager.core.ui.action.deleteEntry") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new DeleteKeyHandler();
+ }
+
+ },
+ REFRESH("com.motorolamobility.studio.android.certmanager.core.ui.action.refresh") //$NON-NLS-1$
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new RefreshHandler();
+ }
+
+ },
+ CHANGE_KEYSTORE_TYPE(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.changeKeystoreType")
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ChangeKeyStoreTypeHandler();
+ }
+ },
+ IMPORT_KEYSTORE_ENTRIES(
+ "com.motorolamobility.studio.android.certmanager.core.ui.action.importKeystoreEntries")
+ {
+ @Override
+ public IHandler getHandler()
+ {
+ return new ImportKeyStoreEntriesHandler();
+ }
+ };
+
+ private final String actionId;
+
+ private ActionHandlers(String actionId)
+ {
+ this.actionId = actionId;
+ }
+
+ public abstract IHandler getHandler();
+
+ public static ActionHandlers getActionHandlerbyId(String id)
+ {
+
+ Object ret = null;
+ for (ActionHandlers h : ActionHandlers.values())
+ {
+ if (h.actionId.equals(id))
+ {
+ ret = h;
+ break;
+ }
+ }
+
+ return (ActionHandlers) ret;
+ }
+ }
+
+ @Override
+ public void run(IAction action)
+ {
+
+ ActionHandlers type = ActionHandlers.getActionHandlerbyId(action.getId());
+
+ IHandler handler = null;
+
+ if (type != null)
+ {
+ handler = type.getHandler();
+ }
+
+ if (handler != null)
+ {
+ ExecutionEvent event = new ExecutionEvent();
+ try
+ {
+ handler.execute(event);
+ }
+ catch (ExecutionException e)
+ {
+ StudioLogger.error(PopupMenuActionDelegate.class, e.getMessage(), e);
+ EclipseUtils.showErrorDialog("Execution error", e.getMessage());
+ }
+ }
+
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection)
+ {
+ //selection is retrieved by the handlers
+ }
+
+ @Override
+ public void setActivePart(IAction action, IWorkbenchPart targetPart)
+ {
+ //do nothing
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java new file mode 100644 index 0000000..dc029cd --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/RemoveSignatureAction.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.ui.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +import com.motorolamobility.studio.android.certmanager.ui.wizards.RemoveExternalPackageSignatureWizard; + +/** + * This class gets the current workspace selection and calls the wizard to remove a package signature + */ +public class RemoveSignatureAction extends Action +{ + /* + * (non-Javadoc) + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() + { + IWorkbench workbench = PlatformUI.getWorkbench(); + + if ((workbench != null) && !workbench.isClosing()) + { + + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + + if (window != null) + { + ISelection selection = window.getSelectionService().getSelection(); + IStructuredSelection structureSelection = null; + + if (selection instanceof IStructuredSelection) + { + structureSelection = (IStructuredSelection) selection; + } + else + { + structureSelection = new StructuredSelection(); + } + WizardDialog dialog = + new WizardDialog(window.getShell(), + new RemoveExternalPackageSignatureWizard(structureSelection)); + dialog.open(); + } + } + + } +}
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java new file mode 100644 index 0000000..c02b20a --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/action/SignCreatedPackageAction.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.ui.action; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry; +import com.motorolamobility.studio.android.certmanager.ui.wizards.SignExternalPackageWizard; + +/** + * This class gets the current workspace selection and calls the wizard to Sign an existent package + */ +public class SignCreatedPackageAction extends Action +{ + + /* + * (non-Javadoc) + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() + { + IWorkbench workbench = PlatformUI.getWorkbench(); + + if ((workbench != null) && !workbench.isClosing()) + { + + IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); + + if (window != null) + { + ISelection selection = window.getSelectionService().getSelection(); + IStructuredSelection structureSelection = null; + IKeyStore selectedIKeyStore = null; + IKeyStoreEntry selectedEntry = null; + if (selection instanceof IStructuredSelection) + { + structureSelection = (IStructuredSelection) selection; + Object selectedItem = structureSelection.getFirstElement(); + if (selectedItem instanceof IKeyStore) + { + selectedIKeyStore = (IKeyStore) selectedItem; + } + else if (selectedItem instanceof IKeyStoreEntry) + { + selectedEntry = (IKeyStoreEntry) selectedItem; + selectedIKeyStore = selectedEntry.getKeyStoreNode(); + } + } + else + { + structureSelection = new StructuredSelection(); + } + WizardDialog dialog = + new WizardDialog(window.getShell(), new SignExternalPackageWizard( + structureSelection, selectedIKeyStore, selectedEntry)); + dialog.open(); + + } + } + } + +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java new file mode 100644 index 0000000..2e1f70e --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/CertificateBlock.java @@ -0,0 +1,495 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.composite;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import com.motorola.studio.android.common.utilities.ui.Country;
+import com.motorola.studio.android.common.utilities.ui.ToolsCountries;
+import com.motorola.studio.android.common.utilities.ui.WidgetsFactory;
+import com.motorola.studio.android.common.utilities.ui.WidgetsUtil;
+import com.motorola.studio.android.wizards.elements.IBaseBlock;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * This class shows the properties to for certificate.
+ */
+public class CertificateBlock implements IBaseBlock
+{
+ private static final String LABEL_DECORATOR = "*"; //$NON-NLS-1$
+
+ private static final int LONG_TEXT_SIZE = 256;
+
+ private static final int MEDIUM_TEXT_SIZE = 128;
+
+ private static final int SMALL_TEXT_SIZE = 64;
+
+ /**
+ * The attribute representing the window with which the user interacts.
+ */
+ private Shell shell;
+
+ /**
+ * Store the composite.
+ */
+ protected Composite parent;
+
+ /**
+ * The key pair alias text field.
+ */
+ private Text textAlias;
+
+ /**
+ * The common name text field.
+ */
+ private Text commonNameText;
+
+ /**
+ * The organization text field.
+ */
+ private Text textOrganization;
+
+ /**
+ * The organization unit text field.
+ */
+ private Text textOrganizationUnit;
+
+ /**
+ * The locality text field.
+ */
+ private Text textLocality;
+
+ /**
+ * The state text field.
+ */
+ private Text textState;
+
+ /**
+ * The country combo.
+ */
+ private Combo comboCountry;
+
+ private Label labelAlias;
+
+ private Control controlToFocus = null;
+
+ /**
+ * This listener is used to save the field that has the focus.
+ * */
+ protected FocusListener focusListener = new FocusListener()
+ {
+
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ //do nothing...
+ }
+
+ @Override
+ public void focusGained(FocusEvent e)
+ {
+ if (e.widget instanceof Control)
+ {
+ controlToFocus = (Control) e.widget;
+ }
+ }
+ };
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.android.wizards.BaseWizard#
+ * createContentPlugin(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Composite createContent(Composite parent)
+ {
+ Composite toReturn = WidgetsFactory.createComposite(parent, 1);
+
+ this.parent = parent;
+
+ createBasicInfoArea(toReturn);
+ createDetailedInfoArea(toReturn);
+ createCustomArea(toReturn);
+ setDefaultFocus();
+
+ return toReturn;
+ }
+
+ protected void createCustomArea(Composite parent)
+ {
+ //by default, do nothing
+ }
+
+ /**
+ * Creates Custom Fields to be appended in the properties block
+ * @param dnFieldsArea
+ */
+ protected void createCustomDetailedInfoArea(Composite dnFieldsArea)
+ {
+ //by default, do nothing
+ }
+
+ /**
+ * Create all fields of the distinguished name.
+ *
+ * @param parent The parent composite to add the created fields.
+ */
+ private void createDetailedInfoArea(Composite parent)
+ {
+ //Composite bottomComposite = WidgetsFactory.createComposite(parent);
+
+ Group detailsGroup =
+ WidgetsFactory.createTitledGroup(parent,
+ CertificateManagerNLS.CertificateBlock_DetailedInfoGroupTitle, 2);
+
+ // Creating the common name field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_FirstAndLastName + ":"); //$NON-NLS-1$
+ commonNameText = WidgetsFactory.createText(detailsGroup);
+ commonNameText.setTextLimit(MEDIUM_TEXT_SIZE);
+ commonNameText.addListener(SWT.Modify, this);
+ commonNameText.addFocusListener(focusListener);
+
+ // Creating the organization field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_Organization + ":"); //$NON-NLS-1$
+ textOrganization = WidgetsFactory.createText(detailsGroup);
+ textOrganization.setTextLimit(MEDIUM_TEXT_SIZE);
+ textOrganization.addListener(SWT.Modify, this);
+ textOrganization.addFocusListener(focusListener);
+
+ // Creating the organization unit field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_OrganizationUnit + ":"); //$NON-NLS-1$
+ textOrganizationUnit = WidgetsFactory.createText(detailsGroup);
+ textOrganizationUnit.setTextLimit(MEDIUM_TEXT_SIZE);
+ textOrganizationUnit.addListener(SWT.Modify, this);
+ textOrganizationUnit.addFocusListener(focusListener);
+
+ // Creating the locality field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_CityOrLocality + ":"); //$NON-NLS-1$
+ textLocality = WidgetsFactory.createText(detailsGroup);
+ textLocality.setTextLimit(LONG_TEXT_SIZE);
+ textLocality.addListener(SWT.Modify, this);
+ textLocality.addFocusListener(focusListener);
+
+ // Creating the state field
+ WidgetsFactory.createLabel(detailsGroup,
+ CertificateManagerNLS.CertificateBlock_StateOrProvince + ":"); //$NON-NLS-1$
+ textState = WidgetsFactory.createText(detailsGroup);
+ textState.setTextLimit(LONG_TEXT_SIZE);
+ textState.addListener(SWT.Modify, this);
+ textState.addFocusListener(focusListener);
+
+ // Creating the country field
+ WidgetsFactory.createLabel(detailsGroup, CertificateManagerNLS.CertificateBlock_CountryCode
+ + ":"); //$NON-NLS-1$
+ comboCountry = WidgetsFactory.createCombo(detailsGroup);
+ comboCountry.addListener(SWT.Selection, this);
+ comboCountry.addFocusListener(focusListener);
+ for (Country country : ToolsCountries.getInstance().getCountries())
+ {
+ this.comboCountry.add(country.getCountryName());
+ this.comboCountry.setData(country.getCountryName(), country.getCountryCode());
+ }
+ comboCountry.setVisibleItemCount(SMALL_TEXT_SIZE);
+
+ createCustomDetailedInfoArea(detailsGroup);
+ }
+
+ /**
+ * Create the key pair alias field.
+ *
+ * @param parent The parent composite to add the key pair alias field.
+ */
+ private void createBasicInfoArea(Composite parent)
+ {
+ Group groupBasicInfo =
+ WidgetsFactory.createTitledGroup(parent,
+ CertificateManagerNLS.CertificateBlock_BasicInfoGroupTitle, 2);
+
+ labelAlias =
+ WidgetsFactory.createLabel(groupBasicInfo,
+ CertificateManagerNLS.CertificateBlock_AliasName + ":"); //$NON-NLS-1$
+ textAlias = WidgetsFactory.createText(groupBasicInfo);
+ textAlias.setTextLimit(SMALL_TEXT_SIZE);
+ textAlias.addListener(SWT.Modify, this);
+ textAlias.addFocusListener(focusListener);
+
+ createCustomBasicInfoArea(groupBasicInfo);
+ }
+
+ /**
+ * Allow subclasses to add custom required fields to the certificate block.
+ * @param parent The parent composite for the custom required fields.
+ */
+ protected void createCustomBasicInfoArea(Composite parent)
+ {
+ //default implementation does nothing.
+ }
+
+ /**
+ * Decorate required fields using {@link CertificateBlock#decorateText(String)}. Always call the {@code super} implementation when overriding this method.
+ * <br/>
+ * Default required fields are:
+ * <ul>
+ * <li>Alias</li>
+ * </ul>
+ * */
+ protected void decorateRequiredFields()
+ {
+ labelAlias.setText(decorateText(labelAlias.getText()));
+ }
+
+ /**
+ * Decorate required fields by prefixing it with {@link CertificateBlock#LABEL_DECORATOR}.
+ *
+ * @return The decorated text.
+ * */
+ protected String decorateText(String strToDecorate)
+ {
+ return LABEL_DECORATOR.concat(strToDecorate);
+ }
+
+ /**
+ * Obtains the key pair alias defined by user.
+ *
+ * @return The key pair alias.
+ */
+ public String getAlias()
+ {
+ return textAlias.getText().toLowerCase();
+ }
+
+ /**
+ * Obtains the common name defined by user.
+ *
+ * @return The common name.
+ */
+ public String getCommonName()
+ {
+ return commonNameText.getText();
+ }
+
+ /**
+ * Obtains the organization defined by user.
+ *
+ * @return The organization.
+ */
+ public String getOrganization()
+ {
+ return textOrganization.getText();
+ }
+
+ /**
+ * Obtains the organization unit defined by user.
+ *
+ * @return The organization unit.
+ */
+ public String getOrganizationUnit()
+ {
+ return textOrganizationUnit.getText();
+ }
+
+ /**
+ * Obtains the locality defined by user.
+ *
+ * @return The locality.
+ */
+ public String getLocality()
+ {
+ return textLocality.getText();
+ }
+
+ /**
+ * Obtains the state defined by user.
+ *
+ * @return The state.
+ */
+ public String getState()
+ {
+ return textState.getText();
+ }
+
+ /**
+ * Obtains the country defined by user.
+ *
+ * @return The country.
+ */
+ public String getCountry()
+ {
+ String result = new String(); //empty string
+
+ //ensure that there is something selected in the combo before indexing its item list
+ if (comboCountry.getSelectionIndex() >= 0)
+ {
+ result =
+ (String) comboCountry.getData(comboCountry.getItem(comboCountry
+ .getSelectionIndex()));
+ }
+ return result;
+ }
+
+ /**
+ * Returns true if there is no error message set, the alias is not empty and there is at least one detail field non empty.
+ * @see com.motorola.studio.platform.tools.common.ui.composite.BaseBlock#isPageComplete()
+ */
+ @Override
+ public boolean isPageComplete()
+ {
+ return (getErrorMessage() == null)
+ && !WidgetsUtil.isNullOrEmpty(this.textAlias)
+ && (!WidgetsUtil.isNullOrEmpty(this.commonNameText)
+ || !WidgetsUtil.isNullOrEmpty(this.textOrganization)
+ || !WidgetsUtil.isNullOrEmpty(this.textOrganizationUnit)
+ || !WidgetsUtil.isNullOrEmpty(this.textLocality)
+ || !WidgetsUtil.isNullOrEmpty(this.textState) || !WidgetsUtil
+ .isNullOrDeselected(this.comboCountry));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.platform.tools.common.ui.composite.BaseBlock#
+ * canFlipToNextPage()
+ */
+ @Override
+ public boolean canFlipToNextPage()
+ {
+ return (getErrorMessage() == null) && isPageComplete();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.platform.tools.common.ui.composite.BaseBlock#
+ * getErrorMessage()
+ */
+ @Override
+ public String getErrorMessage()
+ {
+ String toReturn = null;
+
+ if (WidgetsUtil.isNullOrEmpty(textAlias))
+ {
+ toReturn =
+ CertificateManagerNLS.bind(CertificateManagerNLS.CertificateBlock_FieldIsEmpty,
+ CertificateManagerNLS.CertificateBlock_AliasName);
+ }
+ else if (WidgetsUtil.isNullOrEmpty(commonNameText)
+ && (WidgetsUtil.isNullOrEmpty(textOrganization))
+ && (WidgetsUtil.isNullOrEmpty(textOrganizationUnit))
+ && (WidgetsUtil.isNullOrEmpty(textLocality))
+ && (WidgetsUtil.isNullOrEmpty(textState))
+ && (WidgetsUtil.isNullOrDeselected(comboCountry)))
+ {
+ toReturn = CertificateManagerNLS.CertificateBlock_DetailedInfoNonEmptyFieldsRestriction;
+ }
+
+ return toReturn;
+ }
+
+ public Composite createInfoBlock(Composite parent, String alias, String name,
+ String organization, String organizationUnit, String country, String state,
+ String locality)
+ {
+ Composite toReturn = createContent(parent);
+ textAlias.setText(alias);
+ commonNameText.setText(name);
+ textOrganization.setText(organization);
+ textOrganizationUnit.setText(organizationUnit);
+ textLocality.setText(locality);
+ textState.setText(state);
+ int i = 0;
+ boolean found = false;
+ while ((i < comboCountry.getItemCount()) && !found)
+ {
+ String id = (String) comboCountry.getData(comboCountry.getItem(i));
+ if (id.equalsIgnoreCase(country))
+ {
+ comboCountry.select(i);
+ found = true;
+ }
+ i++;
+ }
+
+ textAlias.setEditable(false);
+ commonNameText.setEditable(false);
+ textOrganization.setEditable(false);
+ textOrganizationUnit.setEditable(false);
+ textLocality.setEditable(false);
+ textState.setEditable(false);
+ if (!found)
+ {
+ comboCountry.add(CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty, 0);
+ comboCountry.select(0);
+ }
+ comboCountry.setEnabled(false);
+
+ return toReturn;
+ }
+
+ @Override
+ public void handleEvent(Event event)
+ {
+ if (this.parent != null)
+ {
+ this.parent.notifyListeners(event.type, event);
+ }
+ }
+
+ @Override
+ public void refresh()
+ {
+ // Empty
+ }
+
+ @Override
+ public void setShell(Shell shell)
+ {
+ this.shell = shell;
+ }
+
+ @Override
+ public Shell getShell()
+ {
+ return shell;
+ }
+
+ @Override
+ public void setDefaultFocus()
+ {
+ controlToFocus = textAlias;
+ }
+
+ @Override
+ public void setFocus()
+ {
+ if (controlToFocus != null)
+ {
+ controlToFocus.setFocus();
+ }
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java new file mode 100644 index 0000000..f0b97f6 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/KeyPropertiesBlock.java @@ -0,0 +1,74 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.composite;
+
+import java.util.Date;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+import com.motorola.studio.android.common.utilities.ui.WidgetsFactory;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * This class shows the properties to for Android certificates / keys.
+ */
+public class KeyPropertiesBlock extends CertificateBlock
+{
+ private Label labelExpirationDate = null;
+
+ private Text textExpirationDate = null;
+
+ private Label labelCreationDate = null;
+
+ private Text textCreationDate = null;
+
+ @Override
+ protected void createCustomDetailedInfoArea(Composite parent)
+ {
+ labelCreationDate =
+ WidgetsFactory.createLabel(parent,
+ CertificateManagerNLS.CertificateBlock_CreationDate + ":"); //$NON-NLS-1$
+ textCreationDate = WidgetsFactory.createText(parent);
+
+ labelExpirationDate =
+ WidgetsFactory.createLabel(parent,
+ CertificateManagerNLS.CertificateBlock_ExpirationDate + ":"); //$NON-NLS-1$
+ textExpirationDate = WidgetsFactory.createText(parent);
+ }
+
+ public Composite createInfoBlock(Composite parent, String alias, String name,
+ String organization, String organizationUnit, String country, String state,
+ String locality, Date validity, Date creationDate)
+ {
+ Composite toReturn =
+ super.createInfoBlock(parent, alias, name, organization, organizationUnit, country,
+ state, locality);
+ labelCreationDate.setText(CertificateManagerNLS.CertificateBlock_CreationDate + ":"); //$NON-NLS-1$
+ labelCreationDate.setVisible(true);
+ textCreationDate.setTextLimit(Text.LIMIT);
+ textCreationDate.setText(creationDate.toString());
+ textCreationDate.setEditable(false);
+
+ labelExpirationDate.setText(CertificateManagerNLS.CertificateBlock_ExpirationDate + ":"); //$NON-NLS-1$
+ textExpirationDate.setTextLimit(Text.LIMIT);
+ textExpirationDate.setText(validity.toString());
+ textExpirationDate.setEditable(false);
+
+ return toReturn;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java new file mode 100644 index 0000000..dfeea6f --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/composite/NewKeyBlock.java @@ -0,0 +1,303 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.composite;
+
+import java.util.Date;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+
+import com.motorola.studio.android.common.utilities.ui.WidgetsFactory;
+import com.motorola.studio.android.common.utilities.ui.WidgetsUtil;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizardPage;
+
+/**
+ * This class shows the field to create a new Android certificates / keys.
+ */
+public class NewKeyBlock extends CertificateBlock
+{
+ private static final int VALIDITY_SIZE = 3;
+
+ private static final int SMALL_TEXT_SIZE = 64;
+
+ private CreateKeyWizardPage baseWizardPage;
+
+ private Label keyPasswordLabel;
+
+ private Label keyConfirmPasswordLabel;
+
+ private Text keyPassword;
+
+ private Text keyConfirmPassword;
+
+ private Button savePasswordCheckBox;
+
+ private Text textValidity = null;
+
+ private Label labelValidity = null;
+
+ private boolean canSavePassword = false;
+
+ private String keyPasswordText = new String();
+
+ private static final String DEFAULT_VALIDITY_IN_YEARS = "30"; //default //$NON-NLS-1$
+
+ @Override
+ public Composite createContent(Composite parent)
+ {
+ Composite composite = super.createContent(parent);
+
+ decorateRequiredFields();
+
+ return composite;
+ };
+
+ @Override
+ protected void createCustomDetailedInfoArea(Composite parent)
+ {
+ labelValidity =
+ WidgetsFactory.createLabel(parent, CertificateManagerNLS.CertificateBlock_Validity
+ + ":"); //$NON-NLS-1$
+ textValidity = WidgetsFactory.createText(parent);
+ textValidity.addListener(SWT.Modify, this);
+ textValidity.addFocusListener(focusListener);
+ textValidity.setTextLimit(VALIDITY_SIZE);
+ textValidity.setText(DEFAULT_VALIDITY_IN_YEARS);
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.ui.composite.CertificateBlock#createCustomArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected void createCustomArea(Composite parent)
+ {
+ Group passwordGroup =
+ WidgetsFactory.createTitledGroup(parent,
+ CertificateManagerNLS.NewKeyBlock_PasswordGroupTitle, 2);
+
+ //KEYSTORE PASSWORD SECTION
+ keyPasswordLabel = new Label(passwordGroup, SWT.NONE);
+ keyPasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keyPasswordLabel.setText(CertificateManagerNLS.CertificateBlock_KeyPassword_Label + ":"); //$NON-NLS-2$ //$NON-NLS-1$
+
+ keyPassword = new Text(passwordGroup, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keyPassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keyPassword.setTextLimit(SMALL_TEXT_SIZE);
+ keyPassword.addListener(SWT.Modify, new Listener()
+ {
+ @Override
+ public void handleEvent(Event event)
+ {
+ keyPasswordText = keyPassword.getText();
+ NewKeyBlock.super.handleEvent(event);
+ }
+ });
+
+ keyPassword.addFocusListener(focusListener);
+
+ //CONFIRM PASSWORD SECTION
+ keyConfirmPasswordLabel = new Label(passwordGroup, SWT.NONE);
+ keyConfirmPasswordLabel
+ .setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keyConfirmPasswordLabel
+ .setText(CertificateManagerNLS.CertificateBlock_ConfirmKeyPassword_Label + ":"); //$NON-NLS-2$ //$NON-NLS-1$
+
+ keyConfirmPassword = new Text(passwordGroup, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keyConfirmPassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keyConfirmPassword.addListener(SWT.Modify, this);
+ keyConfirmPassword.addFocusListener(focusListener);
+ keyConfirmPassword.setTextLimit(SMALL_TEXT_SIZE);
+
+ //Creates the save password checkbox
+ savePasswordCheckBox = new Button(passwordGroup, SWT.CHECK);
+ savePasswordCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ savePasswordCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword);
+ savePasswordCheckBox.setSelection(false);
+ savePasswordCheckBox.addFocusListener(focusListener);
+
+ if ((baseWizardPage != null) && (baseWizardPage.getKeystore() != null))
+ {
+ //we can not save password if keystore is not mapped in the view
+ savePasswordCheckBox.setVisible(KeyStoreManager.getInstance().isKeystoreMapped(
+ baseWizardPage.getKeystore().getFile()));
+ }
+ savePasswordCheckBox.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ //update according to check status
+ canSavePassword = savePasswordCheckBox.getSelection();
+ }
+
+ });
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.ui.composite.CertificateBlock#decorateRequiredFields()
+ */
+ @Override
+ protected void decorateRequiredFields()
+ {
+ super.decorateRequiredFields();
+
+ labelValidity.setText(decorateText(labelValidity.getText()));
+ keyPasswordLabel.setText(decorateText(keyPasswordLabel.getText()));
+ keyConfirmPasswordLabel.setText(decorateText(keyConfirmPasswordLabel.getText()));
+ }
+
+ @Override
+ public boolean isPageComplete()
+ {
+ return (super.isPageComplete()) && !WidgetsUtil.isNullOrEmpty(this.textValidity)
+ && !WidgetsUtil.isNullOrEmpty(this.keyPassword)
+ && !WidgetsUtil.isNullOrEmpty(this.keyConfirmPassword);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.platform.tools.common.ui.composite.BaseBlock#
+ * canFlipToNextPage()
+ */
+ @Override
+ public boolean canFlipToNextPage()
+ {
+ return super.canFlipToNextPage() && !WidgetsUtil.isNullOrEmpty(this.textValidity)
+ && !WidgetsUtil.isNullOrEmpty(this.keyPassword)
+ && !WidgetsUtil.isNullOrEmpty(this.keyConfirmPassword);
+ }
+
+ public Composite createInfoBlock(Composite parent, String alias, String name,
+ String organization, String organizationUnit, String country, String state,
+ String locality, Date validity, Date creationDate)
+ {
+ Composite toReturn =
+ super.createInfoBlock(parent, alias, name, organization, organizationUnit, country,
+ state, locality);
+ labelValidity.setText(CertificateManagerNLS.CertificateBlock_ExpirationDate + ":"); //$NON-NLS-1$
+ textValidity.setTextLimit(Text.LIMIT);
+ textValidity.setText(validity.toString());
+ textValidity.setEditable(false);
+
+ keyPasswordLabel.setVisible(false);
+ keyPassword.setVisible(false);
+ keyConfirmPasswordLabel.setVisible(false);
+ keyConfirmPassword.setVisible(false);
+ savePasswordCheckBox.setVisible(false);
+
+ return toReturn;
+ }
+
+ public String getKeyPassword()
+ {
+ return keyPasswordText;
+ }
+
+ public String getKeyConfirmPassword()
+ {
+ return keyConfirmPassword.getText();
+ }
+
+ public boolean needToSaveKeyPassword()
+ {
+ return canSavePassword;
+ }
+
+ @Override
+ public String getErrorMessage()
+ {
+ String message = super.getErrorMessage();
+
+ //if there is no error message on other items => check text validity field
+ if (message == null)
+ {
+ try
+ {
+ int validity = Integer.parseInt(textValidity.getText());
+ if (validity <= 0)
+ {
+ throw new NumberFormatException();
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ message = CertificateManagerNLS.CertificateBlock_Validity_Error; //$NON-NLS-1$
+ }
+ }
+
+ //if there is no error message on other items => check password fields
+ if (message == null)
+ {
+ //password text and confirmation password text must match
+ if (!keyPassword.getText().equals(keyConfirmPassword.getText()))
+ {
+ message = CertificateManagerNLS.CreateKeystorePage_PasswordDoesNotMatch;
+ }
+ //check password size according to keytool specification
+ if (keyPassword.getText().length() < EntryNode.KEY_PASSWORD_MIN_SIZE)
+ {
+ message =
+ CertificateManagerNLS.bind(
+ CertificateManagerNLS.CreateKeystorePage_PasswordMinSizeMessage,
+ IKeyStore.KEYSTORE_PASSWORD_MIN_SIZE); //$NON-NLS-1$
+ }
+
+ }
+
+ return message;
+ }
+
+ /**
+ * Set messages (used to set information messages)
+ * @param message
+ * @param messageType IMessageProvider.INFORMATION
+ */
+ protected void setMessage(String message, int messageType)
+ {
+ if (baseWizardPage != null)
+ {
+ baseWizardPage.setMessage(message, messageType);
+ }
+ }
+
+ public String getValidity()
+ {
+ return textValidity.getText();
+ }
+
+ /**
+ * @param baseWizardPage the baseWizardPage to set
+ */
+ public void setBaseWizardPage(CreateKeyWizardPage baseWizardPage)
+ {
+ this.baseWizardPage = baseWizardPage;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java new file mode 100644 index 0000000..ec916ea --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupContentProvider.java @@ -0,0 +1,53 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+public class BackupContentProvider implements IStructuredContentProvider
+{
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ Object[] elements = null;
+ if (inputElement instanceof List)
+ {
+ elements = ((List<?>) inputElement).toArray();
+ }
+ else if (inputElement instanceof String[])
+ {
+ elements = (String[]) inputElement;
+ }
+ return elements;
+ }
+
+}
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java new file mode 100644 index 0000000..65cd6ed --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupDialog.java @@ -0,0 +1,400 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+public class BackupDialog extends TitleAreaDialog
+{
+
+ private static final String ZIP_EXT = ".zip"; //$NON-NLS-1$
+
+ private static final String WIZARD_BANNER = "icons/wizban/backup_keystore_wiz.png"; //$NON-NLS-1$
+
+ private static final String BACKUP_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".backup_keystore"; //$NON-NLS-1$;
+
+ private final IContentProvider contentProvider;
+
+ private final IBaseLabelProvider labelProvider;
+
+ private CheckboxTableViewer tableViewer;
+
+ private Object input;
+
+ private final String title;
+
+ private File archiveFile;
+
+ private List<String> selectedKeyStores;
+
+ private String archivePath;
+
+ private boolean verifyOverwrite;
+
+ private Button selectAllButton;
+
+ public BackupDialog(Shell parentShell)
+ {
+ super(parentShell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ this.contentProvider = new BackupContentProvider();
+ this.labelProvider = new BackupLabelProvider();
+ this.title = CertificateManagerNLS.BackupDialog_Diag_Title;
+ this.archivePath = ""; //$NON-NLS-1$
+ selectedKeyStores = new ArrayList<String>();
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ getShell().setText(title);
+ setTitle(CertificateManagerNLS.BackupDialog_DialogTitle);
+ //the shell has the same help as its page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), BackupDialog.BACKUP_KEYSTORE_HELP_ID);
+
+ Composite dialogArea = new Composite(parent, SWT.FILL);
+ dialogArea.setLayout(new GridLayout());
+ dialogArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Group pathGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ pathGroup.setText(CertificateManagerNLS.BackupDialog_Backup_File);
+ pathGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ pathGroup.setLayout(new GridLayout(3, false));
+
+ Label pathLabel = new Label(pathGroup, SWT.NONE);
+ pathLabel.setText(CertificateManagerNLS.BackupDialog_Path);
+ pathLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Text pathText = new Text(pathGroup, SWT.BORDER);
+ pathText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ pathText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ archivePath = pathText.getText();
+ archiveFile = new File(archivePath);
+ verifyOverwrite = true;
+ validate();
+ }
+ });
+
+ Button browseButton = new Button(pathGroup, SWT.PUSH);
+ browseButton.setText(CertificateManagerNLS.BackupDialog_Browse);
+ browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ browseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ FileDialog fileDialog = new FileDialog(getShell(), SWT.SAVE);
+ fileDialog.setFilterExtensions(new String[]
+ {
+ "*" + ZIP_EXT //$NON-NLS-1$
+ });
+ fileDialog.setOverwrite(true);
+ String choosenPath = fileDialog.open();
+ pathText.setText(choosenPath);
+ verifyOverwrite = false;
+ super.widgetSelected(e);
+ }
+ });
+
+ Group keystoresGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ keystoresGroup.setText(CertificateManagerNLS.BackupDialog_KeyStores);
+ keystoresGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ keystoresGroup.setLayout(new GridLayout(1, false));
+
+ tableViewer =
+ CheckboxTableViewer.newCheckList(keystoresGroup, SWT.H_SCROLL | SWT.V_SCROLL
+ | SWT.CHECK | SWT.BORDER);
+ tableViewer.setContentProvider(contentProvider);
+ tableViewer.setLabelProvider(labelProvider);
+ tableViewer.setInput(input);
+ selectKeystores();
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.widthHint = 400;
+ layoutData.heightHint = 200;
+ tableViewer.getControl().setLayoutData(layoutData);
+ tableViewer.addCheckStateListener(new ICheckStateListener()
+ {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event)
+ {
+ String keyStore = null;
+ Object element = event.getElement();
+ if (element instanceof String)
+ {
+ keyStore = (String) element;
+ }
+
+ if (keyStore != null)
+ {
+ if (event.getChecked())
+ {
+ selectedKeyStores.add(keyStore);
+ }
+ else
+ {
+ selectedKeyStores.remove(keyStore);
+ }
+ }
+
+ updateSelectAllState();
+
+ validate();
+ }
+ });
+ Composite selectButtonArea = new Composite(keystoresGroup, SWT.NONE);
+ selectButtonArea.setLayout(new GridLayout(1, true));
+ selectButtonArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ selectAllButton = new Button(selectButtonArea, SWT.CHECK);
+ selectAllButton.setText(CertificateManagerNLS.BackupDialog_Select_All);
+ selectAllButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+ selectAllButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableViewer.setAllChecked(selectAllButton.getSelection());
+ selectedKeyStores.clear();
+
+ for (Object element : tableViewer.getCheckedElements())
+ {
+ String keyStoreEl = (String) element;
+ selectedKeyStores.add(keyStoreEl);
+ }
+ validate();
+ super.widgetSelected(e);
+ }
+ });
+
+ updateSelectAllState();
+
+ setMessage(CertificateManagerNLS.BackupDialog_Default_Message);
+ return dialogArea;
+ }
+
+ private void updateSelectAllState()
+ {
+ if (tableViewer.getCheckedElements().length == tableViewer.getTable().getItems().length)
+ {
+ selectAllButton.setSelection(true);
+ }
+ else
+ {
+ selectAllButton.setSelection(false);
+ }
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control buttonBar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return buttonBar;
+ }
+
+ @Override
+ protected void okPressed()
+ {
+ boolean canContinue = true;
+ if (verifyOverwrite && archiveFile.exists())
+ {
+ boolean canOvewrite =
+ EclipseUtils.showQuestionDialog(
+ CertificateManagerNLS.BackupDialog_Archive_Exists_Title, NLS.bind(
+ CertificateManagerNLS.BackupDialog_Archive_Exists_Message,
+ archiveFile));
+
+ if (!canOvewrite)
+ {
+ canContinue = false;
+ }
+ else
+ {
+ archiveFile.delete();
+ }
+ }
+
+ if (canContinue)
+ {
+ if (!FileUtil.canWrite(archiveFile))
+ {
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.BackupDialog_Fail_Writing_Archive_Title, NLS.bind(
+ CertificateManagerNLS.BackupDialog_Fail_Writing_Archive_Message,
+ archiveFile));
+
+ }
+ else
+ {
+ setErrorMessage(null);
+ super.okPressed();
+ }
+ }
+ }
+
+ private void validate()
+ {
+
+ boolean isValid = true;
+ boolean hasWarn = false;
+ Path path = new Path(archivePath);
+ try
+ {
+ if (archivePath.isEmpty() || !path.isValidPath(archiveFile.getCanonicalPath()))
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Invalid_Destination_Title);
+ isValid = false;
+ }
+ }
+ catch (IOException e)
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Invalid_Destination_Title);
+ isValid = false;
+ }
+
+ if (isValid)
+ {
+ if (archiveFile.exists() && (archiveFile.isDirectory()))
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Invalid_Destination_Message);
+ isValid = false;
+ }
+ }
+
+ if (isValid)
+ {
+ if (!archiveFile.isAbsolute())
+ {
+ setMessage(
+ NLS.bind(CertificateManagerNLS.BackupDialog_Non_Absolute_Path,
+ archiveFile.getAbsolutePath()), IMessageProvider.WARNING);
+ hasWarn = true;
+ }
+ }
+
+ if (isValid)
+ {
+ if (selectedKeyStores.isEmpty())
+ {
+ setErrorMessage(CertificateManagerNLS.BackupDialog_Select_KeyStore);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ if (!hasWarn)
+ {
+ setMessage(CertificateManagerNLS.BackupDialog_Default_Message);
+ }
+ isValid = true;
+ }
+ }
+
+ getButton(OK).setEnabled(isValid);
+ }
+
+ public void setInput(Object input)
+ {
+ if (tableViewer != null)
+ {
+ tableViewer.setInput(input);
+ }
+ this.input = input;
+ }
+
+ /**
+ * @return the Archive file to be created
+ */
+ public File getArchiveFile()
+ {
+ return archiveFile.getName().toLowerCase().endsWith(ZIP_EXT) ? archiveFile : new File(
+ archivePath + ZIP_EXT);
+ }
+
+ /**
+ * @return the Keystores file paths to be archived
+ */
+ public List<String> getSelectedKeyStores()
+ {
+ return selectedKeyStores;
+ }
+
+ public void selectKeyStores(List<ITreeNode> keystores)
+ {
+ for (ITreeNode treeNode : keystores)
+ {
+ if (treeNode instanceof IKeyStore)
+ {
+ IKeyStore keystore = (IKeyStore) treeNode;
+ selectedKeyStores.add(keystore.getFile().getAbsolutePath());
+ }
+ }
+ }
+
+ private void selectKeystores()
+ {
+ for (TableItem item : tableViewer.getTable().getItems())
+ {
+ item.setChecked(selectedKeyStores.contains(item.getText()));
+ }
+ }
+
+}
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java new file mode 100644 index 0000000..6e4fa90 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/BackupLabelProvider.java @@ -0,0 +1,66 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.swt.graphics.Image;
+
+public class BackupLabelProvider implements ILabelProvider
+{
+
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property)
+ {
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+ return null;
+ }
+
+ @Override
+ public String getText(Object element)
+ {
+ String text = null;
+ if (element instanceof String)
+ {
+ text = (String) element;
+ }
+ return text;
+ }
+
+}
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java new file mode 100644 index 0000000..53fbbf3 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/CertificateInfoDialog.java @@ -0,0 +1,139 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.composite.KeyPropertiesBlock;
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+
+/**
+ * Dialog to show certificate info.
+ */
+public class CertificateInfoDialog extends Dialog
+{
+ private static final String HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".certificate_info_dialog"; //$NON-NLS-1$
+
+ final private KeyPropertiesBlock block;
+
+ final private EntryNode entry;
+
+ public CertificateInfoDialog(Shell parentShell, KeyPropertiesBlock blk, EntryNode entry)
+ {
+ super(parentShell);
+ this.block = blk;
+ this.entry = entry;
+ }
+
+ @Override
+ protected Control createContents(Composite parent)
+ {
+ if (parent instanceof Shell)
+ {
+ ((Shell) parent).setText(CertificateManagerNLS.CertificateInfoDialog_ShellTitle);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, HELP_ID);
+ }
+ return super.createContents(parent);
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent)
+ {
+ createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ Composite newComposite = (Composite) super.createDialogArea(parent);
+ X509Certificate cert = null;
+
+ try
+ {
+ cert = entry.getX509Certificate();
+
+ if (cert != null)
+ {
+ X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
+ RDN commonName =
+ x500name.getRDNs(BCStyle.CN).length >= 1 ? x500name.getRDNs(BCStyle.CN)[0]
+ : null;
+ RDN organization =
+ x500name.getRDNs(BCStyle.O).length >= 1 ? x500name.getRDNs(BCStyle.O)[0]
+ : null;
+ RDN organizationUnit =
+ x500name.getRDNs(BCStyle.OU).length >= 1 ? x500name.getRDNs(BCStyle.OU)[0]
+ : null;
+ RDN country =
+ x500name.getRDNs(BCStyle.C).length >= 1 ? x500name.getRDNs(BCStyle.C)[0]
+ : null;
+ RDN state =
+ x500name.getRDNs(BCStyle.ST).length >= 1 ? x500name.getRDNs(BCStyle.ST)[0]
+ : null;
+ RDN locality =
+ x500name.getRDNs(BCStyle.L).length >= 1 ? x500name.getRDNs(BCStyle.L)[0]
+ : null;
+
+ block.createInfoBlock(newComposite, entry.getAlias(), printCertInfo(commonName),
+ printCertInfo(organization), printCertInfo(organizationUnit),
+ printCertInfo(country), printCertInfo(state), printCertInfo(locality),
+ cert.getNotAfter(), cert.getNotBefore());
+ }
+ else
+ {
+ //not found Android certificate expected (X509Certificate)
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.CertificateInfoDialog_UnknownCertificateKeypairType,
+ CertificateManagerNLS.CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties);
+ }
+ }
+ catch (Exception e)
+ {
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties,
+ e.getMessage());
+ StudioLogger
+ .error(CertificateInfoDialog.class,
+ CertificateManagerNLS.CertificatePropertiesHandler_ErrorGettingCertificateOrKeypairProperties,
+ e);
+ }
+ return newComposite;
+ }
+
+ private String printCertInfo(RDN certItem)
+ {
+ return certItem != null ? certItem.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java new file mode 100644 index 0000000..64f364c --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/RestoreBackupDialog.java @@ -0,0 +1,437 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.command.BackupHandler;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+public class RestoreBackupDialog extends TitleAreaDialog
+{
+
+ private static final String ZIP_EXT = "*.zip"; //$NON-NLS-1$
+
+ private static final String WIZARD_BANNER = "icons/wizban/restore_keystore_wiz.png"; //$NON-NLS-1$
+
+ public static final String RESTORE_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".restore_keystore"; //$NON-NLS-1$
+
+ private final IContentProvider contentProvider;
+
+ private final IBaseLabelProvider labelProvider;
+
+ private CheckboxTableViewer tableViewer;
+
+ private final String title;
+
+ private File archiveFile;
+
+ private List<String> selectedKeyStores;
+
+ private File destinationFile;
+
+ private Button selectAllButton;
+
+ private String destinationPath = ""; //$NON-NLS-1$
+
+ public RestoreBackupDialog(Shell parentShell)
+ {
+ super(parentShell);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ this.contentProvider = new BackupContentProvider();
+ this.labelProvider = new BackupLabelProvider();
+ this.title = CertificateManagerNLS.RestoreBackupDialog_Dialog_Title;
+ selectedKeyStores = new ArrayList<String>();
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ getShell().setText(title);
+ setTitle(CertificateManagerNLS.RestoreBackupDialog_TitleArea_Message);
+
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), RestoreBackupDialog.RESTORE_KEYSTORE_HELP_ID);
+
+ Composite dialogArea = new Composite(parent, SWT.FILL);
+ dialogArea.setLayout(new GridLayout());
+ dialogArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Group pathGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ pathGroup.setText(CertificateManagerNLS.RestoreBackupDialog_Path_Group);
+ pathGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ pathGroup.setLayout(new GridLayout(3, false));
+
+ Label pathLabel = new Label(pathGroup, SWT.NONE);
+ pathLabel.setText(CertificateManagerNLS.RestoreBackupDialog_BackUp_File);
+ pathLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Text pathText = new Text(pathGroup, SWT.BORDER);
+ pathText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ pathText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ archiveFile = new File(pathText.getText());
+ selectAllButton.setSelection(false);
+ validate();
+ loadArchiveEntries();
+ }
+ });
+
+ Button browseButton = new Button(pathGroup, SWT.PUSH);
+ browseButton.setText(CertificateManagerNLS.RestoreBackupDialog_Browse_Button);
+ browseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ browseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ FileDialog fileDialog = new FileDialog(getShell());
+ fileDialog.setFilterExtensions(new String[]
+ {
+ ZIP_EXT
+ });
+ fileDialog.setOverwrite(false);
+ String choosenPath = fileDialog.open();
+ pathText.setText(choosenPath);
+ super.widgetSelected(e);
+ }
+ });
+
+ Label destinPath = new Label(pathGroup, SWT.NONE);
+ destinPath.setText(CertificateManagerNLS.RestoreBackupDialog_Destination);
+ destinPath.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
+
+ final Text destinText = new Text(pathGroup, SWT.BORDER);
+ destinText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ destinText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ destinationPath = destinText.getText();
+ destinationFile = new File(destinationPath);
+ validate();
+ }
+ });
+
+ Button destinBrowseButton = new Button(pathGroup, SWT.PUSH);
+ destinBrowseButton.setText(CertificateManagerNLS.RestoreBackupDialog_Browse_Button);
+ destinBrowseButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ destinBrowseButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ DirectoryDialog directoryDialog = new DirectoryDialog(getShell());
+ String choosenPath = directoryDialog.open();
+ destinText.setText(choosenPath);
+ super.widgetSelected(e);
+ }
+ });
+
+ Group keystoresGroup = new Group(dialogArea, SWT.SHADOW_NONE);
+ keystoresGroup.setText(CertificateManagerNLS.RestoreBackupDialog_KeyStores);
+ keystoresGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ keystoresGroup.setLayout(new GridLayout(1, false));
+
+ tableViewer =
+ CheckboxTableViewer.newCheckList(keystoresGroup, SWT.H_SCROLL | SWT.V_SCROLL
+ | SWT.CHECK | SWT.BORDER);
+ tableViewer.setContentProvider(contentProvider);
+ tableViewer.setLabelProvider(labelProvider);
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ layoutData.widthHint = 400;
+ layoutData.heightHint = 200;
+ tableViewer.getControl().setLayoutData(layoutData);
+ tableViewer.addCheckStateListener(new ICheckStateListener()
+ {
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event)
+ {
+ String keyStore = null;
+ Object element = event.getElement();
+ if (element instanceof String)
+ {
+ keyStore = (String) element;
+ }
+
+ if (keyStore != null)
+ {
+ if (event.getChecked())
+ {
+ selectedKeyStores.add(keyStore);
+ }
+ else
+ {
+ selectedKeyStores.remove(keyStore);
+ }
+ }
+
+ if (tableViewer.getCheckedElements().length == tableViewer.getTable().getItems().length)
+ {
+ selectAllButton.setSelection(true);
+ }
+ else
+ {
+ selectAllButton.setSelection(false);
+ }
+
+ validate();
+ }
+ });
+
+ Composite selectButtonArea = new Composite(keystoresGroup, SWT.NONE);
+ selectButtonArea.setLayout(new GridLayout(1, true));
+ selectButtonArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ selectAllButton = new Button(selectButtonArea, SWT.CHECK);
+ selectAllButton.setText(CertificateManagerNLS.RestoreBackupDialog_Select_All);
+ selectAllButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+ selectAllButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ tableViewer.setAllChecked(selectAllButton.getSelection());
+ selectedKeyStores.clear();
+ for (Object element : tableViewer.getCheckedElements())
+ {
+ String keyStoreEl = (String) element;
+ selectedKeyStores.add(keyStoreEl);
+ }
+ validate();
+ super.widgetSelected(e);
+ }
+ });
+
+ setMessage(CertificateManagerNLS.RestoreBackupDialog_Default_Message);
+ return dialogArea;
+ }
+
+ protected void loadArchiveEntries()
+ {
+ Runnable loadRunnable = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (archiveFile.exists())
+ {
+ @SuppressWarnings("rawtypes")
+ final List[] holderArray = new List[1];
+
+ ZipFile zipFile = null;
+ try
+ {
+ zipFile = new ZipFile(archiveFile, ZipFile.OPEN_READ);
+ ArrayList<String> keyStores = new ArrayList<String>(zipFile.size());
+ holderArray[0] = keyStores;
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements())
+ {
+ ZipEntry zipEntry = entries.nextElement();
+ if (!zipEntry.getName().equalsIgnoreCase(
+ BackupHandler.KS_TYPES_FILENAME))
+ {
+ keyStores.add(zipEntry.getName());
+ }
+ }
+ Display.getDefault().syncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ tableViewer.setInput(holderArray[0]);
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ Display.getDefault().asyncExec(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ clearKeystoresTableViewer();
+ setErrorMessage(NLS
+ .bind(CertificateManagerNLS.RestoreBackupDialog_Error_Loading_Entries,
+ archiveFile));
+ getButton(OK).setEnabled(false);
+ }
+ });
+ }
+ finally
+ {
+ if (zipFile != null)
+ {
+ try
+ {
+ zipFile.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger
+ .error("Could not close stream while restoring backup. "
+ + e.getMessage());
+ }
+ }
+ }
+ }
+ }
+ };
+
+ Thread thread = new Thread(loadRunnable);
+ thread.start();
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control buttonBar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return buttonBar;
+ }
+
+ private void validate()
+ {
+
+ boolean isValid = true;
+
+ if (!archiveFile.exists())
+ {
+ clearKeystoresTableViewer();
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_BackUpFile_Not_Exist);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ isValid = true;
+ }
+
+ if (isValid)
+ {
+ if (destinationPath.isEmpty())
+ {
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_Invalid_Dest_Path);
+ isValid = false;
+ }
+ else
+ {
+ if ((destinationFile != null) && destinationFile.isFile())
+ {
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_Invalid_Dest_Path);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ isValid = true;
+ }
+ }
+ }
+
+ if (isValid)
+ {
+ if (selectedKeyStores.isEmpty())
+ {
+ setErrorMessage(CertificateManagerNLS.RestoreBackupDialog_Select_KeyStore);
+ isValid = false;
+ }
+ else
+ {
+ setErrorMessage(null);
+ isValid = true;
+ }
+ }
+
+ getButton(OK).setEnabled(isValid);
+ }
+
+ /**
+ * Remove all entries from keystores table viewer.
+ * */
+ private void clearKeystoresTableViewer()
+ {
+ tableViewer.setInput(null);
+ }
+
+ /**
+ * @return The back archive file
+ */
+ public File getArchiveFile()
+ {
+ return archiveFile;
+ }
+
+ /**
+ * @return The keystores to be restored
+ */
+ public List<String> getSelectedKeyStores()
+ {
+ return selectedKeyStores;
+ }
+
+ /**
+ * @return The destination directory
+ */
+ public File getDestinationDir()
+ {
+ return destinationFile;
+ }
+
+}
\ No newline at end of file diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java new file mode 100644 index 0000000..aa697b4 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ConvertKeyStoreTypeDialog.java @@ -0,0 +1,633 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs.importks;
+
+import java.io.File;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PasswordProtection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class ConvertKeyStoreTypeDialog extends TitleAreaDialog
+{
+ public class EntryModel
+ {
+
+ private final String alias;
+
+ private String passwd;
+
+ private boolean verified;
+
+ public EntryModel(String alias)
+ {
+ this.alias = alias;
+ try
+ {
+ String savedPass = keyStore.getPasswordProvider().getPassword(alias, false);
+ setPasswd(savedPass != null ? savedPass : ""); //$NON-NLS-1$
+ }
+ catch (KeyStoreManagerException e)
+ {
+ setPasswd(""); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return alias;
+ }
+
+ public String getPasswd()
+ {
+ return passwd;
+ }
+
+ public void setPasswd(String passwd)
+ {
+ this.passwd = passwd;
+ try
+ {
+ Entry entry =
+ keyStore.getKeyStore().getEntry(alias,
+ new PasswordProtection(passwd.toCharArray()));
+ setVerified(entry != null);
+ }
+ catch (Exception e)
+ {
+ setVerified(false);
+ }
+ aliaseMap.put(alias, passwd);
+ }
+
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ public boolean isVerified()
+ {
+ return verified;
+ }
+
+ private void setVerified(boolean verified)
+ {
+ this.verified = verified;
+ validateUi();
+ }
+ }
+
+ public class EntriesContentProvider implements IStructuredContentProvider
+ {
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ List<EntryModel> modelList = null;
+ if (inputElement instanceof List<?>)
+ {
+ List<?> inputList = (List<?>) inputElement;
+ modelList = new ArrayList<EntryModel>(inputList.size());
+ Iterator<?> it = inputList.iterator();
+ while (it.hasNext())
+ {
+ Object element = it.next();
+ if (element instanceof String) //received an alias
+ {
+ String alias = (String) element;
+ EntryModel entryModel = new EntryModel(alias);
+ modelList.add(entryModel);
+ }
+ }
+
+ }
+ return modelList.toArray();
+ }
+
+ }
+
+ private final class PasswordEditingSupport extends EditingSupport
+ {
+ private PasswordEditingSupport(ColumnViewer viewer)
+ {
+ super(viewer);
+ }
+
+ @Override
+ protected boolean canEdit(Object element)
+ {
+ return true;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element)
+ {
+ return new TextCellEditor(entriesTable, SWT.PASSWORD);
+ }
+
+ @Override
+ protected Object getValue(Object element)
+ {
+ return ((EntryModel) element).getPasswd();
+ }
+
+ @Override
+ protected void setValue(Object element, Object value)
+ {
+ EntryModel model = (EntryModel) element;
+ model.setPasswd((String) value);
+ getViewer().update(element, null);
+ }
+ }
+
+ private static final String HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".convert_keystore_type"; //$NON-NLS-1$
+
+ private static final String WIZARD_BANNER = "icons/wizban/change_keystore_type_wiz.png"; //$NON-NLS-1$
+
+ private IKeyStore keyStore;
+
+ private String newType = ""; //$NON-NLS-1$
+
+ private Text passwdText;
+
+ private String password = ""; //$NON-NLS-1$
+
+ private Table entriesTable;
+
+ private TableViewer entriesTableViewer;
+
+ private final Map<String, String> aliaseMap = new HashMap<String, String>();
+
+ /**
+ * Create the dialog.
+ * @param parentShell
+ */
+ public ConvertKeyStoreTypeDialog(Shell parentShell, IKeyStore keyStore)
+ {
+ super(parentShell);
+ setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+
+ this.keyStore = keyStore;
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ /**
+ * Create contents of the dialog.
+ * @param parent
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ parent.getShell().setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DialogTitle);
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DefaultMessage);
+ setTitle(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DialogTitle);
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayout(new GridLayout(1, false));
+ container.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Composite convertTopComposite = new Composite(container, SWT.NONE);
+ convertTopComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
+ convertTopComposite.setLayout(new GridLayout(1, false));
+
+ Composite keyStoreComposite = new Composite(convertTopComposite, SWT.NONE);
+ keyStoreComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ keyStoreComposite.setLayout(new GridLayout(3, false));
+
+ Label keyStoreLabel = new Label(keyStoreComposite, SWT.NONE);
+ keyStoreLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_KeyStoreLabel);
+
+ final Combo keyStoreCombo = new Combo(keyStoreComposite, SWT.READ_ONLY);
+ keyStoreCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ final KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ try
+ {
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ File ksFile = keyStore.getFile();
+ String comboItem = ksFile.getName() + " - " + ksFile.getAbsolutePath(); //$NON-NLS-1$
+ keyStoreCombo.add(comboItem);
+ keyStoreCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(this.keyStore))
+ {
+ keyStoreCombo.select(keyStoreCombo.indexOf(comboItem));
+ }
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_CouldNotLoad_Keystores_Error);
+ }
+
+ Label passwdLabel = new Label(keyStoreComposite, SWT.NONE);
+ passwdLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ passwdLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Password_Label);
+
+ passwdText = new Text(keyStoreComposite, SWT.BORDER | SWT.PASSWORD);
+ passwdText.addModifyListener(new ModifyListener()
+ {
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ password = passwdText.getText();
+ }
+ });
+ passwdText.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ super.widgetDefaultSelected(e);
+ loadEntries();
+ }
+ });
+ passwdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ Button loadButton = new Button(keyStoreComposite, SWT.NONE);
+ GridData gd_loadButton = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ gd_loadButton.widthHint = 80;
+ loadButton.setLayoutData(gd_loadButton);
+ loadButton.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Load_Button);
+ loadButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ loadEntries();
+ }
+ });
+
+ Composite composite_1 = new Composite(convertTopComposite, SWT.NONE);
+ GridData gd_composite_1 = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
+ gd_composite_1.heightHint = 39;
+ composite_1.setLayoutData(gd_composite_1);
+ composite_1.setLayout(new GridLayout(4, false));
+
+ Label typeLabel = new Label(composite_1, SWT.NONE);
+ typeLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Original_Type_Label);
+
+ final Label currentTypeLabel = new Label(composite_1, SWT.NONE);
+ GridData gd_currentTypeLabel = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
+ gd_currentTypeLabel.widthHint = 90;
+ gd_currentTypeLabel.minimumWidth = 90;
+ currentTypeLabel.setLayoutData(gd_currentTypeLabel);
+ currentTypeLabel.setText(keyStore.getType());
+
+ Label newTypeLabel = new Label(composite_1, SWT.NONE);
+ newTypeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ newTypeLabel.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_NewType_Label);
+
+ final Combo typeCombo = new Combo(composite_1, SWT.READ_ONLY);
+ typeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ loadTypeCombo(keyStoreManager, typeCombo);
+ new Label(composite_1, SWT.NONE);
+ new Label(composite_1, SWT.NONE);
+ new Label(composite_1, SWT.NONE);
+ new Label(composite_1, SWT.NONE);
+
+ typeCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ newType = typeCombo.getText();
+ validateUi();
+ }
+ });
+
+ keyStoreCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ updateUi(keyStoreCombo, keyStoreManager, currentTypeLabel, typeCombo);
+ validateUi();
+ }
+ });
+
+ Group entriesGroup = new Group(container, SWT.NONE);
+ entriesGroup.setLayout(new GridLayout(1, true));
+ GridData gd_entriesGroup = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gd_entriesGroup.heightHint = 230;
+ gd_entriesGroup.widthHint = 433;
+ entriesGroup.setLayoutData(gd_entriesGroup);
+ entriesGroup.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Entries_Group);
+
+ entriesTableViewer =
+ new TableViewer(entriesGroup, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION);
+ entriesTableViewer.setContentProvider(new EntriesContentProvider());
+ entriesTable = entriesTableViewer.getTable();
+ entriesTable.setHeaderVisible(true);
+ entriesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+
+ TableViewerColumn aliasViewerColumn = new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnAlias = aliasViewerColumn.getColumn();
+ tblclmnAlias.setWidth(100);
+ tblclmnAlias.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Alias_Column);
+ aliasViewerColumn.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getAlias();
+ }
+ });
+
+ TableViewerColumn passwordViewerColumn_1 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ passwordViewerColumn_1.setEditingSupport(new PasswordEditingSupport(entriesTableViewer));
+ TableColumn tblclmnPassword = passwordViewerColumn_1.getColumn();
+ tblclmnPassword.setWidth(100);
+ tblclmnPassword.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Password_Column);
+ passwordViewerColumn_1.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getPasswd().replaceAll(".", "*"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ });
+
+ TableViewerColumn verifiedViewerColumn_2 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnVerified = verifiedViewerColumn_2.getColumn();
+ tblclmnVerified.setWidth(130);
+ tblclmnVerified.setText(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Verified_Column);
+ verifiedViewerColumn_2.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).isVerified()
+ ? CertificateManagerNLS.ConvertKeyStoreTypeDialog_Verified_Pass_Yes
+ : CertificateManagerNLS.ConvertKeyStoreTypeDialog_Verified_Pass_Wrong;
+ }
+ });
+
+ updateUi(keyStoreCombo, keyStoreManager, currentTypeLabel, typeCombo);
+
+ return area;
+ }
+
+ @Override
+ protected Control createHelpControl(Composite parent)
+ {
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent.getShell(), HELP_ID);
+ return super.createHelpControl(parent);
+ }
+
+ private void updateUi(final Combo keyStoreCombo, final KeyStoreManager keyStoreManager,
+ final Label currentTypeLabel, final Combo typeCombo)
+ {
+ keyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ try
+ {
+ password = keyStore.getPasswordProvider().getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+
+ if (password == null)
+ {
+ password = ""; //$NON-NLS-1$
+ }
+ passwdText.setText(password);
+ if (!password.isEmpty())
+ {
+ IKeyStore keyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ currentTypeLabel.setText(keyStore.getType());
+ loadTypeCombo(keyStoreManager, typeCombo);
+ aliaseMap.clear();
+ try
+ {
+ if (keyStore.isPasswordValid(password))
+ {
+ List<String> aliases;
+ aliases = keyStore.getAliases(password);
+ entriesTableViewer.setInput(aliases);
+ }
+ else
+ {
+ validateUi();
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+ catch (InvalidPasswordException e)
+ {
+ validateUi();
+ }
+ }
+ }
+
+ private void loadEntries()
+ {
+ try
+ {
+ aliaseMap.clear();
+ List<String> aliases = keyStore.getAliases(password);
+ entriesTableViewer.setInput(aliases);
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Error_Loading_Keystore);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ catch (InvalidPasswordException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ validateUi();
+ }
+
+ private void loadTypeCombo(KeyStoreManager keyStoreManager, final Combo typeCombo)
+ {
+ typeCombo.setItems(new String[0]);
+ List<String> availableTypes = keyStoreManager.getAvailableTypes();
+ for (String type : availableTypes)
+ {
+ if (!type.equals(keyStore.getType()))
+ {
+ typeCombo.add(type);
+ }
+ }
+ typeCombo.clearSelection();
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control bar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return bar;
+ }
+
+ public void validateUi()
+ {
+ boolean isValid = true;
+ setErrorMessage(null);
+ if (isValid && (keyStore == null))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Choose_KeyStore_Msg);
+ }
+ if (isValid)
+ {
+ boolean passwordValid;
+ try
+ {
+ passwordValid = keyStore.isPasswordValid(password);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ passwordValid = false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ passwordValid = false;
+ }
+ if (!passwordValid)
+ {
+ isValid = false;
+ setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass);
+ }
+ }
+ if (isValid && newType.isEmpty())
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Choose_New_Type_Msg);
+ }
+ if (isValid)
+ {
+ Object input = entriesTableViewer.getInput();
+ if (input != null)
+ {
+ int itemCount = ((List<?>) input).size();
+ for (int i = 0; i < itemCount; i++)
+ {
+ EntryModel entryModel = (EntryModel) entriesTableViewer.getElementAt(i);
+ if ((entryModel != null) && !entryModel.isVerified())
+ {
+ isValid = false;
+ setMessage(
+ CertificateManagerNLS.ConvertKeyStoreTypeDialog_Incorrect_Entry_Pass,
+ IMessageProvider.WARNING);
+ break;
+ }
+ }
+ }
+ }
+
+ Button okButton = getButton(OK);
+ if (okButton != null)
+ {
+ if (!isValid)
+ {
+ okButton.setEnabled(false);
+ }
+ else
+ {
+ getButton(OK).setEnabled(true);
+ setErrorMessage(null);
+ setMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_DefaultMessage);
+ }
+ }
+ }
+
+ public IKeyStore getKeyStore()
+ {
+ return keyStore;
+ }
+
+ public String getNewType()
+ {
+ return newType;
+ }
+
+ public Map<String, String> getAliases()
+ {
+ return aliaseMap;
+ }
+
+ public String getKeystorePassword()
+ {
+ return this.password;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java new file mode 100644 index 0000000..0a1cf31 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/dialogs/importks/ImportEntriesDialog.java @@ -0,0 +1,675 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.dialogs.importks;
+
+import java.io.File;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PasswordProtection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class ImportEntriesDialog extends TitleAreaDialog
+{
+ public class EntryModel
+ {
+ private final String alias;
+
+ private String passwd;
+
+ private boolean verified;
+
+ public EntryModel(String alias)
+ {
+ this.alias = alias;
+ try
+ {
+ String savedPass = sourceKeyStore.getPasswordProvider().getPassword(alias, false);
+ setPasswd(savedPass != null ? savedPass : ""); //$NON-NLS-1$
+ }
+ catch (KeyStoreManagerException e)
+ {
+ setPasswd(""); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return alias;
+ }
+
+ public String getPasswd()
+ {
+ return passwd;
+ }
+
+ public void setPasswd(String passwd)
+ {
+ this.passwd = passwd;
+ try
+ {
+ Entry entry =
+ sourceKeyStore.getKeyStore().getEntry(alias,
+ new PasswordProtection(passwd.toCharArray()));
+ setVerified(entry != null);
+ }
+ catch (Exception e)
+ {
+ setVerified(false);
+ }
+ aliasMap.put(alias, passwd);
+ }
+
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ public boolean isVerified()
+ {
+ return verified;
+ }
+
+ private void setVerified(boolean verified)
+ {
+ this.verified = verified;
+ // entriesTableViewer.update(this, null);
+ validateUi();
+ }
+ }
+
+ public class EntriesContentProvider implements IStructuredContentProvider
+ {
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ validateUi();
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ List<EntryModel> modelList = null;
+ if (inputElement instanceof List<?>)
+ {
+ List<?> inputList = (List<?>) inputElement;
+ modelList = new ArrayList<EntryModel>(inputList.size());
+ Iterator<?> it = inputList.iterator();
+ while (it.hasNext())
+ {
+ Object element = it.next();
+ if (element instanceof String) //received an alias
+ {
+ String alias = (String) element;
+ EntryModel entryModel = new EntryModel(alias);
+ modelList.add(entryModel);
+ }
+ }
+
+ }
+ return modelList.toArray();
+ }
+
+ }
+
+ private final class PasswordEditingSupport extends EditingSupport
+ {
+ private PasswordEditingSupport(ColumnViewer viewer)
+ {
+ super(viewer);
+ }
+
+ @Override
+ protected boolean canEdit(Object element)
+ {
+ return true;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element)
+ {
+ return new TextCellEditor(entriesTable, SWT.PASSWORD);
+ }
+
+ @Override
+ protected Object getValue(Object element)
+ {
+ return ((EntryModel) element).getPasswd();
+ }
+
+ @Override
+ protected void setValue(Object element, Object value)
+ {
+ EntryModel model = (EntryModel) element;
+ model.setPasswd((String) value);
+ getViewer().update(element, null);
+ }
+ }
+
+ private static final String WIZARD_BANNER = "icons/wizban/import_entries_wiz.png"; //$NON-NLS-1$
+
+ private static final String HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".import_entries_dialog"; //$NON-NLS-1$
+
+ private IKeyStore sourceKeyStore;
+
+ private IKeyStore targetKeyStore;
+
+ private Text passwdText;
+
+ protected String sourcePassword = ""; //$NON-NLS-1$
+
+ private Table entriesTable;
+
+ private CheckboxTableViewer entriesTableViewer;
+
+ private final Map<String, String> aliasMap = new HashMap<String, String>();
+
+ private Combo keyStoreCombo;
+
+ private Combo targetKsCombo;
+
+ protected List<String> selectedAlias = new ArrayList<String>();
+
+ /**
+ * Create the dialog.
+ * @param parentShell
+ */
+ public ImportEntriesDialog(Shell parentShell, IKeyStore keyStore)
+ {
+ super(parentShell);
+ setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+
+ this.targetKeyStore = keyStore;
+ setTitleImage(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER).createImage());
+ }
+
+ /**
+ * Create contents of the dialog.
+ * @param parent
+ */
+ @Override
+ protected Control createDialogArea(Composite parent)
+ {
+ parent.getShell().setText(CertificateManagerNLS.ImportKeyStoreDialog_Dialog_Title);
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Default_Message);
+ setTitle(CertificateManagerNLS.ImportKeyStoreDialog_Dialog_Title);
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayout(new GridLayout(1, false));
+ container.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Group SourceGroup = new Group(container, SWT.NONE);
+ SourceGroup.setText(CertificateManagerNLS.ImportKeyStoreDialog_Source_Group);
+ SourceGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ SourceGroup.setLayout(new GridLayout(1, false));
+
+ Composite keyStoreComposite = new Composite(SourceGroup, SWT.NONE);
+ keyStoreComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
+ keyStoreComposite.setLayout(new GridLayout(3, false));
+
+ Label keyStoreLabel = new Label(keyStoreComposite, SWT.NONE);
+ keyStoreLabel.setText(CertificateManagerNLS.ImportKeyStoreDialog_KeyStore_Label);
+
+ keyStoreCombo = new Combo(keyStoreComposite, SWT.READ_ONLY);
+ keyStoreCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ Label passwdLabel = new Label(keyStoreComposite, SWT.NONE);
+ passwdLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ passwdLabel.setText(CertificateManagerNLS.ImportKeyStoreDialog_Password_Label);
+
+ passwdText = new Text(keyStoreComposite, SWT.BORDER | SWT.PASSWORD);
+ passwdText.addModifyListener(new ModifyListener()
+ {
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ sourcePassword = passwdText.getText();
+ }
+ });
+ passwdText.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ super.widgetDefaultSelected(e);
+ loadEntries();
+ }
+ });
+ passwdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ Button loadButton = new Button(keyStoreComposite, SWT.NONE);
+ GridData gd_loadButton = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+ gd_loadButton.widthHint = 80;
+ loadButton.setLayoutData(gd_loadButton);
+ loadButton.setText(CertificateManagerNLS.ImportKeyStoreDialog_Load_Button);
+
+ Composite entriesComposite = new Composite(SourceGroup, SWT.NONE);
+ GridData gd_entriesComposite = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gd_entriesComposite.heightHint = 200;
+ entriesComposite.setLayoutData(gd_entriesComposite);
+ entriesComposite.setLayout(new GridLayout(1, true));
+
+ entriesTableViewer =
+ CheckboxTableViewer.newCheckList(entriesComposite, SWT.BORDER | SWT.CHECK
+ | SWT.FULL_SELECTION);
+ entriesTableViewer.setContentProvider(new EntriesContentProvider());
+ entriesTable = entriesTableViewer.getTable();
+ entriesTable.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (e.detail == SWT.CHECK)
+ {
+ validateUi();
+ TableItem item = (TableItem) e.item;
+ if (item.getChecked())
+ {
+ selectedAlias.add(item.getText(0));
+ }
+ else
+ {
+ selectedAlias.remove(item.getText(0));
+ }
+ }
+ }
+ });
+ entriesTable.setHeaderVisible(true);
+ GridData gd_entriesTable = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
+ gd_entriesTable.heightHint = 250;
+ entriesTable.setLayoutData(gd_entriesTable);
+ TableViewerColumn aliasViewerColumn = new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnAlias = aliasViewerColumn.getColumn();
+ tblclmnAlias.setWidth(100);
+ tblclmnAlias.setText(CertificateManagerNLS.ImportKeyStoreDialog_Alias_Column);
+ aliasViewerColumn.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getAlias();
+ }
+ });
+
+ TableViewerColumn passwordViewerColumn_1 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ passwordViewerColumn_1.setEditingSupport(new PasswordEditingSupport(entriesTableViewer));
+ TableColumn tblclmnPassword = passwordViewerColumn_1.getColumn();
+ tblclmnPassword.setWidth(100);
+ tblclmnPassword.setText(CertificateManagerNLS.ImportKeyStoreDialog_Passwd_Column);
+ passwordViewerColumn_1.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).getPasswd().replaceAll(".", "*"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ });
+
+ TableViewerColumn verifiedViewerColumn_2 =
+ new TableViewerColumn(entriesTableViewer, SWT.NONE);
+ TableColumn tblclmnVerified = verifiedViewerColumn_2.getColumn();
+ tblclmnVerified.setWidth(130);
+ tblclmnVerified.setText(CertificateManagerNLS.ImportKeyStoreDialog_Verified_Column);
+ verifiedViewerColumn_2.setLabelProvider(new ColumnLabelProvider()
+ {
+ @Override
+ public String getText(Object element)
+ {
+ return ((EntryModel) element).isVerified()
+ ? CertificateManagerNLS.ImportKeyStoreDialog_Verified_Pass_Yes
+ : CertificateManagerNLS.ImportKeyStoreDialog_Verified_Pass_Wrong;
+ }
+ });
+ loadButton.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ loadEntries();
+ }
+ });
+
+ keyStoreCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ sourceKeyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ IKeyStore keyStore = (IKeyStore) keyStoreCombo.getData(keyStoreCombo.getText());
+ try
+ {
+ sourcePassword = keyStore.getPasswordProvider().getKeyStorePassword(false);
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e1.getMessage());
+ }
+
+ if (sourcePassword == null)
+ {
+ sourcePassword = ""; //$NON-NLS-1$
+ }
+ passwdText.setText(sourcePassword);
+ loadEntries();
+ updateTargetCombo();
+ validateUi();
+ }
+ });
+
+ Group targetGroup = new Group(container, SWT.NONE);
+ targetGroup.setLayout(new GridLayout(2, false));
+ targetGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ targetGroup.setText(CertificateManagerNLS.ImportKeyStoreDialog_Target_Group);
+
+ Label targetKsLabel = new Label(targetGroup, SWT.NONE);
+ targetKsLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ targetKsLabel.setText(CertificateManagerNLS.ImportKeyStoreDialog_KeyStore_Label);
+
+ targetKsCombo = new Combo(targetGroup, SWT.READ_ONLY);
+ targetKsCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ targetKsCombo.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ super.widgetSelected(e);
+ String selectedItem = targetKsCombo.getText();
+ targetKeyStore = (IKeyStore) targetKsCombo.getData(selectedItem);
+ validateUi();
+ }
+ });
+
+ final KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ try
+ {
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ File ksFile = keyStore.getFile();
+ String comboItem = ksFile.getName() + " - " + ksFile.getAbsolutePath(); //$NON-NLS-1$
+ keyStoreCombo.add(comboItem);
+ keyStoreCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(this.sourceKeyStore))
+ {
+ keyStoreCombo.select(keyStoreCombo.indexOf(comboItem));
+ }
+ else
+ {
+ targetKsCombo.add(comboItem);
+ targetKsCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(this.targetKeyStore))
+ {
+ targetKsCombo.select(targetKsCombo.indexOf(comboItem));
+ }
+ }
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Error_Loading_Keystores);
+ }
+
+ return area;
+ }
+
+ @Override
+ protected Control createHelpControl(Composite parent)
+ {
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent.getShell(), HELP_ID);
+ return super.createHelpControl(parent);
+ }
+
+ private void updateTargetCombo()
+ {
+ final KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();
+ try
+ {
+ targetKsCombo.clearSelection();
+ targetKsCombo.setItems(new String[0]);
+ List<IKeyStore> keyStores = keyStoreManager.getKeyStores();
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (keyStore != this.sourceKeyStore)
+ {
+ File ksFile = keyStore.getFile();
+ String comboItem = ksFile.getName() + " - " + ksFile.getAbsolutePath(); //$NON-NLS-1$
+ targetKsCombo.add(comboItem);
+ targetKsCombo.setData(comboItem, keyStore);
+ if (keyStore.equals(targetKeyStore))
+ {
+ targetKsCombo.select(targetKsCombo.indexOf(comboItem));
+ }
+ }
+ }
+ if (targetKsCombo.getSelectionIndex() == -1) //nothing is selected.
+ {
+ targetKeyStore = null;
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Error_Loading_Keystores);
+ }
+
+ }
+
+ private void loadEntries()
+ {
+ try
+ {
+ aliasMap.clear();
+ if (!sourcePassword.isEmpty())
+ {
+ List<String> aliases = sourceKeyStore.getAliases(sourcePassword);
+ entriesTableViewer.setInput(aliases);
+ }
+ else
+ {
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ }
+ catch (KeyStoreManagerException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Error_Loading_Entries);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ catch (InvalidPasswordException e1)
+ {
+ setErrorMessage(CertificateManagerNLS.ImportKeyStoreDialog_Invalid_Keystore_Passwd);
+ entriesTableViewer.setInput(new ArrayList<String>());
+ }
+ }
+
+ @Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control bar = super.createButtonBar(parent);
+ getButton(OK).setEnabled(false);
+ return bar;
+ }
+
+ public void validateUi()
+ {
+ boolean isValid = true;
+ setErrorMessage(null);
+ if (isValid && (sourceKeyStore == null))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Select_Source_Ks);
+ }
+ if (isValid && ((sourcePassword == null) || sourcePassword.isEmpty()))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Type_SourceKs_Passwd);
+ }
+ if (isValid)
+ {
+ try
+ {
+ if (!sourceKeyStore.isPasswordValid(sourcePassword))
+ {
+ isValid = false;
+ setErrorMessage("Wrong source keystore password.");
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ isValid = false;
+ setErrorMessage("Unable to access source keystore.\n" + e.getMessage());
+ }
+ catch (InvalidPasswordException e)
+ {
+ isValid = false;
+ setErrorMessage("Wrong source keystore password.");
+ }
+ }
+ if (isValid)
+ {
+ List<?> input = (List<?>) entriesTableViewer.getInput();
+ if (input != null)
+ {
+ int itemCount = input.size();
+ if (itemCount == 0)
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_No_Entries_To_Import,
+ IMessageProvider.WARNING);
+ }
+ if (entriesTableViewer.getCheckedElements().length == 0)
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_No_Entries_To_Import,
+ IMessageProvider.WARNING);
+ }
+ else
+ {
+ for (int i = 0; i < itemCount; i++)
+ {
+ EntryModel entryModel = (EntryModel) entriesTableViewer.getElementAt(i);
+ if (entriesTableViewer.getChecked(entryModel) && !entryModel.isVerified())
+ {
+ isValid = false;
+ setMessage(
+ CertificateManagerNLS.ImportKeyStoreDialog_Wrong_Entries_Passwd,
+ IMessageProvider.WARNING);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_No_Entries_To_Import,
+ IMessageProvider.WARNING);
+ }
+ }
+ if (isValid && (targetKeyStore == null))
+ {
+ isValid = false;
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Select_Target_Kesytore);
+ }
+
+ if (!isValid)
+ {
+ getButton(OK).setEnabled(false);
+ }
+ else
+ {
+ getButton(OK).setEnabled(true);
+ setErrorMessage(null);
+ setMessage(CertificateManagerNLS.ImportKeyStoreDialog_Default_Message);
+ }
+ }
+
+ public IKeyStore getKeyStore()
+ {
+ return sourceKeyStore;
+ }
+
+ public Map<String, String> getAliases()
+ {
+ Map<String, String> selectedAliasMap = new HashMap<String, String>(selectedAlias.size());
+ for (String alias : selectedAlias)
+ {
+ selectedAliasMap.put(alias, aliasMap.get(alias));
+ }
+ return selectedAliasMap;
+ }
+
+ public IKeyStore getTargetKeyStore()
+ {
+ return targetKeyStore;
+ }
+
+ public String getPassword()
+ {
+ return sourcePassword;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java new file mode 100644 index 0000000..bea7353 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/AbstractTreeNode.java @@ -0,0 +1,139 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Abstract node for {@link KeystoreManagerView}
+ */
+public abstract class AbstractTreeNode implements ITreeNode
+{
+ private static final String UNSAVED_PASSWORD =
+ CertificateManagerNLS.AbstractTreeNode_UnsavedPassword_Tooltip;
+
+ private static final String SAVED_PASSWORD =
+ CertificateManagerNLS.AbstractTreeNode_SavedPassword_Tooltip;
+
+ private IStatus nodeStatus = Status.OK_STATUS;
+
+ private ITreeNode parent;
+
+ private String tooltip;
+
+ @Override
+ public String getTooltip()
+ {
+ if (tooltip != null)
+ {
+ return isPasswordSaved() ? SAVED_PASSWORD + "\n" + tooltip : UNSAVED_PASSWORD //$NON-NLS-1$
+ + "\n" + tooltip; //$NON-NLS-1$
+ }
+ else
+ {
+ return isPasswordSaved() ? SAVED_PASSWORD : UNSAVED_PASSWORD;
+ }
+ }
+
+ /**
+ * @return the nodeStatus
+ */
+ @Override
+ public IStatus getNodeStatus()
+ {
+ return nodeStatus;
+ }
+
+ /**
+ * @param nodeStatus the nodeStatus to set
+ */
+ @Override
+ public void setNodeStatus(IStatus nodeStatus)
+ {
+ this.nodeStatus = nodeStatus;
+ KeyStoreModelEventManager.getInstance().fireEvent(this, EventType.UPDATE);
+ }
+
+ /**
+ * @param tooltip the tooltip to set
+ */
+ @Override
+ public void setTooltip(String tooltip)
+ {
+ this.tooltip = tooltip;
+ }
+
+ /**
+ * @return the parent
+ */
+ @Override
+ public ITreeNode getParent()
+ {
+ return parent;
+ }
+
+ /**
+ * @param parent the parent to set
+ */
+ public void setParent(ITreeNode parent)
+ {
+ this.parent = parent;
+ }
+
+ @Override
+ public void addChild(ITreeNode newChild) throws KeyStoreManagerException
+ {
+ //Default implementation won't do nothing
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = false;
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_ERROR))
+ {
+ result = !getNodeStatus().isOK(); //true if there is an error
+ if (result)
+ {
+ setTooltip(getNodeStatus().getMessage());
+ }
+ }
+ else if (value.equals(PROP_VALUE_NODE_STATUS_OK))
+ {
+ result = getNodeStatus().isOK();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * For dummy nodes and root nodes it is false. Override for other nodes: {@link KeyStoreNode} and {@link EntryNode}
+ * @return
+ */
+ protected boolean isPasswordSaved()
+ {
+ return false;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java new file mode 100644 index 0000000..3d83690 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/CertificateDetailsInfo.java @@ -0,0 +1,140 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public class CertificateDetailsInfo
+{
+ private String alias;
+
+ /**
+ * Issuer name
+ */
+ private String commonName;
+
+ /**
+ * Owner name
+ */
+ private String organization;
+
+ private String organizationUnit;
+
+ private String locality;
+
+ private String country;
+
+ private String state;
+
+ private String entryPassword; //this is NOT the keystore password
+
+ private Date expirationDate;
+
+ public CertificateDetailsInfo(String alias, String commonName, String organization,
+ String organizationUnit, String locality, String country, String state,
+ String validity, String entryPassword)
+ {
+ this.alias = alias;
+ this.commonName = commonName;
+ this.organization = organization;
+ this.organizationUnit = organizationUnit;
+ this.locality = locality;
+ this.country = country;
+ this.state = state;
+ this.entryPassword = entryPassword;
+
+ int validityYears = Integer.parseInt(validity);
+
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.YEAR, validityYears);
+
+ this.expirationDate = cal.getTime();
+ }
+
+ /**
+ * @return the alias
+ */
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ /**
+ * @return the commonName
+ */
+ public String getCommonName()
+ {
+ return commonName;
+ }
+
+ /**
+ * @return the organization
+ */
+ public String getOrganization()
+ {
+ return organization;
+ }
+
+ /**
+ * @return the organizationUnit
+ */
+ public String getOrganizationUnit()
+ {
+ return organizationUnit;
+ }
+
+ /**
+ * @return the locality
+ */
+ public String getLocality()
+ {
+ return locality;
+ }
+
+ /**
+ * @return the country
+ */
+ public String getCountry()
+ {
+ return country;
+ }
+
+ /**
+ * @return the expirationDate
+ */
+ public Date getExpirationDate()
+ {
+ return expirationDate;
+ }
+
+ /**
+ * @return the state
+ */
+ public String getState()
+ {
+ return state;
+ }
+
+ /**
+ * @return the keyPassword
+ */
+ public String getEntryPassword()
+ {
+ return entryPassword;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java new file mode 100644 index 0000000..a35b495 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryDummyNode.java @@ -0,0 +1,71 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+public class EntryDummyNode extends AbstractTreeNode implements ITreeNode
+{
+
+ public static final String DUMMY_NODE_ID = "DUMMY_NODE";
+
+ String alias = DUMMY_NODE_ID;
+
+ public EntryDummyNode(ITreeNode keyStoreModel)
+ {
+ setParent(keyStoreModel);
+ alias = DUMMY_NODE_ID;
+ }
+
+ @Override
+ public void refresh()
+ {
+ //default implementation does nothing.
+ }
+
+ @Override
+ public String getId()
+ {
+ return DUMMY_NODE_ID;
+ }
+
+ @Override
+ public String getName()
+ {
+ return "No Keys found";
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return true;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return Collections.emptyList();
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java new file mode 100644 index 0000000..1cf9d66 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/EntryNode.java @@ -0,0 +1,546 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Represents one keystore element in {@link KeystoreManagerView}. It can be
+ * {@link Certificate} or {@link Key}.
+ */
+public class EntryNode extends AbstractTreeNode implements IKeyStoreEntry
+{
+ /**
+ * The constant contains the key pair DER object identifier.
+ */
+ public static final String KEY_PAIR_DER_OBJ_ID = "2.16.840.1.113793.23"; //$NON-NLS-1$
+
+ public static final int KEY_PASSWORD_MIN_SIZE = 6;
+
+ protected String alias;
+
+ private final String KEY_NONSAVED_PASSWORD_ICON_PATH = "icons/key.png"; //$NON-NLS-1$
+
+ private final String KEY_SAVED_PASSWORD_ICON_PATH = "icons/key_saved_password.png"; //$NON-NLS-1$
+
+ protected EntryNode()
+ {
+
+ }
+
+ /**
+ *
+ * @param keyStoreModel
+ * @param alias
+ * @throws KeyStoreManagerException
+ * if the alias is already listed in the tree
+ */
+ public EntryNode(ITreeNode keyStoreModel, String alias) throws KeyStoreManagerException
+ {
+ this.alias = alias.toLowerCase();
+ setParent(keyStoreModel);
+ if (!isKeyPairEntry())
+ {
+ keyStoreModel.addChild(this);
+ }
+
+ // notify key entry addition
+ // KeyStoreModelEventManager.getInstance().fireEvent(this, KeyStoreModelEvent.EventType.ADD);
+
+ // Obtaining certificate to get tooltip information
+ X509Certificate cert = getX509Certificate();
+ if (cert != null)
+ {
+ X500Name x500name;
+ try
+ {
+ x500name = new JcaX509CertificateHolder(cert).getSubject();
+
+ RDN commonName =
+ x500name.getRDNs(BCStyle.CN).length >= 1 ? x500name.getRDNs(BCStyle.CN)[0]
+ : null;
+ RDN organization =
+ x500name.getRDNs(BCStyle.O).length >= 1 ? x500name.getRDNs(BCStyle.O)[0]
+ : null;
+
+ // Adding tooltip information
+ String org =
+ organization != null ? organization.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ String name =
+ commonName != null ? commonName.getFirst().getValue().toString()
+ : CertificateManagerNLS.CertificateInfoDialog_NotAvailableProperty;
+ this.setTooltip(NLS.bind(CertificateManagerNLS.CertificateBlock_KeyTooltip, org,
+ name));
+ }
+ catch (CertificateEncodingException e)
+ {
+ String errorMsg = "Error getting data from certificate";
+ StudioLogger.error(EntryNode.class, errorMsg, e);
+ throw new KeyStoreManagerException(errorMsg, e);
+ }
+ }
+ }
+
+ /*(non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getKeyStoreNode()
+ */
+ @Override
+ public IKeyStore getKeyStoreNode()
+ {
+ return (KeyStoreNode) getParent();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getAlias()
+ */
+ @Override
+ public String getAlias()
+ {
+ return alias;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #isCertificateEntry()
+ */
+ @Override
+ public boolean isCertificateEntry() throws KeyStoreException, KeyStoreManagerException
+ {
+ return getKeyStoreNode().getKeyStore().isCertificateEntry(alias);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #isKeyEntry()
+ */
+ @Override
+ public boolean isKeyEntry() throws KeyStoreException, KeyStoreManagerException
+ {
+ return getKeyStoreNode().getKeyStore().isKeyEntry(alias);
+ }
+
+ @Override
+ public boolean isKeyPairEntry()
+ {
+ X509Certificate certificate = getX509Certificate();
+ Set<String> criticalOIDs = certificate.getCriticalExtensionOIDs();
+ return (criticalOIDs != null) && criticalOIDs.contains(KEY_PAIR_DER_OBJ_ID);
+ }
+
+ /**
+ * @return {@link Certificate} if alias represents a certificate or null if
+ * the alias was not found (or if the type is not Certificate for
+ * the alias)
+ * @throws KeyStoreException
+ * if keystore not loaded yet
+ * @throws KeyStoreManagerException
+ */
+ private Certificate getCertificate() throws KeyStoreException, KeyStoreManagerException
+ {
+ Certificate certificate = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isCertificateEntry(alias))
+ {
+ certificate = keyStore.getCertificate(alias);
+ }
+ else
+ {
+ // unknown type
+ StudioLogger.error(CertificateManagerNLS.bind(
+ CertificateManagerNLS.EntryNode_NotFoundOrTypeWrong, alias));
+ }
+ return certificate;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getKey(java.lang.String)
+ */
+ @Override
+ public Key getKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException
+ {
+ Key key = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isKeyEntry(alias))
+ {
+ key = keyStore.getKey(alias, password.toCharArray());
+ }
+
+ return key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry
+ * #getPrivateKey(java.lang.String)
+ */
+ @Override
+ public PrivateKey getPrivateKey(String password) throws UnrecoverableKeyException,
+ KeyStoreException, NoSuchAlgorithmException, KeyStoreManagerException,
+ InvalidKeyException
+ {
+ Key key = this.getKey(password);
+
+ if (!(key instanceof PrivateKey))
+ {
+ throw new InvalidKeyException("This is not a private key");
+ }
+
+ return (PrivateKey) key;
+ }
+
+ public Entry getKeyEntry(String password) throws KeyStoreException, NoSuchAlgorithmException,
+ KeyStoreManagerException, UnrecoverableEntryException
+ {
+ Entry key = null;
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ if (keyStore.isKeyEntry(alias))
+ {
+ key = keyStore.getEntry(alias, new KeyStore.PasswordProtection(password.toCharArray()));
+ }
+ return key;
+ }
+
+ /**
+ * Get all the certificates associated to this entry
+ *
+ * @return an Array of {@link Certificate}
+ * @throws KeyStoreException
+ * @throws KeyStoreManagerException
+ */
+ private Certificate[] getCertificateChain() throws KeyStoreException, KeyStoreManagerException
+ {
+ KeyStore keyStore = getKeyStoreNode().getKeyStore();
+ return keyStore.getCertificateChain(alias);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((alias == null) ? 0 : alias.hashCode());
+ result =
+ (prime * result) + ((getKeyStoreNode() == null) ? 0 : getKeyStoreNode().hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof EntryNode))
+ {
+ return false;
+ }
+ EntryNode other = (EntryNode) obj;
+ if (alias == null)
+ {
+ if (other.alias != null)
+ {
+ return false;
+ }
+ }
+ else if (!alias.equals(other.alias))
+ {
+ return false;
+ }
+ if (getKeyStoreNode() == null)
+ {
+ if (other.getKeyStoreNode() != null)
+ {
+ return false;
+ }
+ }
+ else if (!getKeyStoreNode().equals(other.getKeyStoreNode()))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return "KeyStoreEntry [alias=" + alias + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public void refresh()
+ {
+ // keys does not need to be refreshed
+ }
+
+ @Override
+ public String getId()
+ {
+ return alias;
+ }
+
+ @Override
+ public String getName()
+ {
+ return alias;
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ //decision: we will not support key-pair, so we will have just key items below keystore node.
+ ImageDescriptor descr = null;
+ if (isPasswordSaved())
+ {
+ //saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, KEY_SAVED_PASSWORD_ICON_PATH);
+ }
+ else
+ {
+ //non saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, KEY_NONSAVED_PASSWORD_ICON_PATH);
+ }
+ return descr;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return true;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return new ArrayList<ITreeNode>(0); // it is the leaf of the tree
+ }
+
+ public static IKeyStoreEntry createSelfSignedNode(IKeyStore keystore, String keyStorePass,
+ String alias, CertificateDetailsInfo certificateDetailsInfo)
+ throws KeyStoreManagerException
+ {
+ KeyPair keyPair = null;
+
+ try
+ {
+ keyPair = KeyStoreUtils.genKeyPair();
+ X509Certificate x509Certificate =
+ KeyStoreUtils.createX509Certificate(keyPair, certificateDetailsInfo);
+
+ if (keyStorePass == null)
+ {
+ PasswordProvider provider = new PasswordProvider(keystore.getFile());
+ keyStorePass = provider.getKeyStorePassword(true);
+ }
+
+ PrivateKeyEntry privateKeyEntry =
+ KeyStoreUtils.createPrivateKeyEntry(keyPair, x509Certificate);
+ KeyStoreUtils.addEntry(keystore.getKeyStore(), keyStorePass.toCharArray(), keystore
+ .getFile(), alias, privateKeyEntry, certificateDetailsInfo.getEntryPassword()
+ .toCharArray());
+
+ //force reload - because keystore cache can be old due to key entries additions/removals
+ keystore.forceReload(keyStorePass.toCharArray(), false);
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreManagerException(e.getMessage(), e);
+ }
+
+ return new EntryNode((ITreeNode) keystore, alias);
+ }
+
+ public static IKeyStoreEntry createSelfSignedNode(IKeyStore keystore, String alias,
+ CertificateDetailsInfo certificateDetailsInfo) throws KeyStoreManagerException
+ {
+ return createSelfSignedNode(keystore, null, alias, certificateDetailsInfo);
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = super.testAttribute(target, name, value);
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_WARNING))
+ {
+ X509Certificate x509Certificate = getX509Certificate();
+ try
+ {
+ // check validity concerning the current date
+ x509Certificate.checkValidity();
+
+ // now check validity related to magic date provided by
+ // Google
+ Calendar date = GregorianCalendar.getInstance();
+ date.clear();
+ date.set(2033, Calendar.OCTOBER, 22);
+ x509Certificate.checkValidity(date.getTime());
+ }
+ catch (CertificateExpiredException e)
+ {
+ // certificate has expired in the current date; or
+ // certificate has expired before 22 Oct 2033
+ setTooltip(CertificateManagerNLS.bind(
+ CertificateManagerNLS.CertificatePeriodExpired_Issue,
+ x509Certificate.getNotAfter()));
+ result = true; // decorate node
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ // certificate is not yet valid in the current date; or
+ // certificate is not yet valid in 2033 => it must not
+ // happen but we need to deal with this case
+ setTooltip(CertificateManagerNLS.bind(
+ CertificateManagerNLS.CertificatePeriodNotYeatValid_Issue,
+ x509Certificate.getNotBefore()));
+ result = true; // decorate node
+ }
+ }
+ }
+ return result;
+
+ }
+
+ /**
+ * Get the first X509Certificate available in the entry
+ *
+ * @return
+ */
+ @Override
+ public X509Certificate getX509Certificate()
+ {
+ X509Certificate x509Certificate = null;
+ try
+ {
+ if (isCertificateEntry())
+ {
+ Certificate cert = getCertificate();
+ if (cert instanceof X509Certificate)
+ {
+ // Android certificate
+ x509Certificate = (X509Certificate) cert;
+ }
+ }
+ else if (isKeyEntry())
+ {
+ Certificate[] chain = getCertificateChain();
+ for (int i = 0; i < chain.length; i++)
+ {
+ Certificate cert = chain[i];
+ if (cert instanceof X509Certificate)
+ {
+ // Android certificate
+ x509Certificate = (X509Certificate) cert;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(EntryNode.class, CertificateManagerNLS.bind(
+ CertificateManagerNLS.EntryNode_ErrorGettingCertificateFromEntry, getAlias()),
+ e);
+ }
+ return x509Certificate;
+ }
+
+ @Override
+ protected boolean isPasswordSaved()
+ {
+ PasswordProvider pp = new PasswordProvider(getKeyStoreNode().getFile());
+ return pp.isPasswordSaved(alias);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java new file mode 100644 index 0000000..53dcc5e --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStore.java @@ -0,0 +1,132 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.util.Date;
+import java.util.List;
+
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+
+public interface IKeyStore
+{
+
+ public int KEYSTORE_PASSWORD_MIN_SIZE = 6;
+
+ public int WRONG_KEYSTORE_TYPE_ERROR_CODE = 1;
+
+ PasswordProvider getPasswordProvider();
+
+ List<String> getAliases(String password) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Returns the {@link KeyStore}
+ * @throws KeyStoreManagerException
+ */
+ KeyStore getKeyStore() throws KeyStoreManagerException;
+
+ /**
+ * Load if needed and returns all entries for this KeyStore
+ * @param password
+ * @return
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ List<IKeyStoreEntry> getEntries(String password) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Load if needed and returns the entry with the given alias.
+ * @param alias The alias of the desired entry.
+ * @param keystorePassword the password of the keystore
+ * @return The desired entry.
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ IKeyStoreEntry getEntry(String alias, String keystorePassword) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * @param password from keystore
+ * Forces keystore reload
+ * @throws KeyStoreManagerException
+ * @throws InvalidPasswordException
+ */
+ void forceReload(char[] charArray, boolean updateUi) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Returns this key store file
+ * @return
+ */
+ File getFile();
+
+ /**
+ * @return this keystore type
+ */
+ String getType();
+
+ /**
+ * Set this keystore type. This is intended to be used only during creation.
+ * This method won't change the keystore type or convert it to another type.
+ * @param type
+ * @throws KeyStoreManagerException
+ */
+ void setType(String type) throws KeyStoreManagerException;
+
+ /**
+ * Set the backup date for this keystore
+ * @param lastBackupDate
+ */
+ void setLastBackupDate(Date lastBackupDate);
+
+ /**
+ * Gets the last backup date for this keystore
+ * @return null if not backed up yet, a date otherwise
+ */
+ Date getLastBackupDate();
+
+ /**
+ * Deletes a key entry with the given alias
+ * @param alias The alias representing the key to be removed.
+ * @throws KeyStoreManagerException
+ */
+ void removeKey(String alias) throws KeyStoreManagerException;
+
+ /**
+ * Deletes a list of key entries from the keystore.
+ * @param aliases The list of aliases representing the keys to be removed.
+ * @throws KeyStoreManagerException
+ */
+ void removeKeys(List<String> aliases) throws KeyStoreManagerException;
+
+ /**
+ * @param password
+ */
+ public boolean isPasswordValid(String password) throws KeyStoreManagerException,
+ InvalidPasswordException;
+
+ /**
+ * Return the password of the keystore.
+ * If the password is not saved and {@code promptPassword} is set to {@code true}, then a dialog will be opened so the user can enter the password.
+ * @return Return the password of the keystore.
+ */
+ String getKeyStorePassword(boolean promptPassword);
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java new file mode 100644 index 0000000..7db617b --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/IKeyStoreEntry.java @@ -0,0 +1,87 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.X509Certificate;
+
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+
+public interface IKeyStoreEntry
+{
+ /**
+ * @return {@link Key} if the alias represents the private key associated to this entry
+ * or null if the alias was not found (or if the type is not Key for the alias)
+ * @throws NoSuchAlgorithmException if no algorithm to recover key not found
+ * @throws KeyStoreException if keystore not loaded yet
+ * @throws UnrecoverableKeyException if wrong password for the key
+ * @throws KeyStoreManagerException
+ */
+ Key getKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException;
+
+ /**
+ * @return The key represented by this node as a PrivateKey.
+ * @throws NoSuchAlgorithmException if no algorithm to recover key not found
+ * @throws KeyStoreException if keystore not loaded yet
+ * @throws UnrecoverableKeyException if wrong password for the key
+ * @throws KeyStoreManagerException
+ * @throws InvalidKeyException If this key is not a {@link PrivateKey}.
+ * */
+ PrivateKey getPrivateKey(String password) throws UnrecoverableKeyException, KeyStoreException,
+ NoSuchAlgorithmException, KeyStoreManagerException, InvalidKeyException;
+
+ /**
+ * @return true if this entry contains a private key
+ * @throws KeyStoreException if the keystore has not been initialized (loaded).
+ * @throws KeyStoreManagerException
+ */
+ boolean isKeyEntry() throws KeyStoreException, KeyStoreManagerException;
+
+ /**
+ * @return true if this entry contains a certificate
+ * @throws KeyStoreException if the keystore has not been initialized (loaded).
+ * @throws KeyStoreManagerException
+ */
+ boolean isCertificateEntry() throws KeyStoreException, KeyStoreManagerException;
+
+ /**
+ * @return true if this entry is a key pair
+ */
+ boolean isKeyPairEntry();
+
+ /**
+ * @return the alias
+ */
+ String getAlias();
+
+ /**
+ * Get the first X509Certificate available in the entry
+ * @return
+ */
+ X509Certificate getX509Certificate();
+
+ /**
+ * @return The keystore node that holds this entry.
+ * */
+ public IKeyStore getKeyStoreNode();
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java new file mode 100644 index 0000000..5edf9de --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/ITreeNode.java @@ -0,0 +1,118 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.security.KeyStoreException;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IActionFilter;
+
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+
+public interface ITreeNode extends IActionFilter
+{
+
+ public static final String PROP_VALUE_NODE_STATUS_OK =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatusOk"; //$NON-NLS-1$
+
+ public static final String PROP_VALUE_NODE_STATUS_KEYSTORE_TYPE_OK =
+ "com.motorolamobility.studio.android.certmanager.core.property.keystoreTypeOk"; //$NON-NLS-1$
+
+ /**
+ * Property value used to check if the node has an error status.
+ */
+ public static final String PROP_VALUE_NODE_STATUS_ERROR =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatusError"; //$NON-NLS-1$
+
+ public static final String PROP_VALUE_NODE_STATUS_WARNING =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatusWarning"; //$NON-NLS-1$
+
+ /**
+ * Property name used to test the status of the node.
+ */
+ public static final String PROP_NAME_NODE_STATUS =
+ "com.motorolamobility.studio.android.certmanager.core.property.nodeStatus"; //$NON-NLS-1$
+
+ public static final String PROP_NAMESPACE =
+ "com.motorolamobility.studio.android.certmanager.core.property";
+
+ /**
+ * Method responsible to reload the node itself and its children
+ */
+ void refresh() throws KeyStoreManagerException;
+
+ /**
+ * @return the id
+ */
+ String getId();
+
+ /**
+ * @return the name
+ */
+ String getName();
+
+ /**
+ * @return the icon
+ */
+ ImageDescriptor getIcon();
+
+ /**
+ * @return true if it does not accept a child, false otherwise
+ */
+ boolean isLeaf();
+
+ /**
+ * Set the node Status, allowing the tree to decorate itself on errors.
+ * Is status is ERROR the icon will be decorated with a error image and tooltip will be replaced by status.getMessage() if available.
+ * @param status
+ */
+ void setNodeStatus(IStatus status);
+
+ /**
+ * Retrieves the current node status.
+ * @return
+ */
+ IStatus getNodeStatus();
+
+ /**
+ * Set the tooltip to be displayed for this node.
+ * @param tooltip
+ */
+ void setTooltip(String tooltip);
+
+ /**
+ * @return this node tooltip text
+ */
+ String getTooltip();
+
+ /**
+ * Get parent of the tree node
+ * @return null if it is the tree root, non-null if is a child node
+ */
+ ITreeNode getParent();
+
+ /**
+ * Retrieves list of children (without any filter)
+ * @return collection of {@link ITreeNode} that are child of this abstract tree node
+ * @throws KeyStoreException
+ * @throws KeyStoreManagerException
+ */
+ List<ITreeNode> getChildren() throws KeyStoreManagerException;
+
+ void addChild(ITreeNode newChild) throws KeyStoreManagerException;
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java new file mode 100644 index 0000000..884fe84 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreNode.java @@ -0,0 +1,786 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.preferences.DialogWithToggleUtils;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreUtils;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent.EventType;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Represents a keystore visual item for the {@link KeystoreManagerView}.
+ *
+ * @author gdpr78
+ *
+ */
+public class KeyStoreNode extends AbstractTreeNode implements IKeyStore
+{
+ public static final String WARN_ABOUT_UNSUPPORTED_ENTRIES_PREFERENCE =
+ CertificateManagerActivator.PLUGIN_ID + ".warnAboutUnsupportedEntries"; //$NON-NLS-1$
+
+ private static final String DUMMY_NODE = "DUMMY_NODE"; //$NON-NLS-1$
+
+ private final File keyStoreFile;
+
+ private KeyStore keyStore;
+
+ private Date lastBackupDate;
+
+ private String type;
+
+ /**
+ * Alias to {@link EntryNode}
+ */
+ private final Map<String, ITreeNode> entries = new LinkedHashMap<String, ITreeNode>();
+
+ private final String KEYSTORE_NONSAVED_PASSWORD_ICON_PATH = "icons/keystore.png"; //$NON-NLS-1$
+
+ private final String KEYSTORE_SAVED_PASSWORD_ICON_PATH = "icons/keystore_saved_password.png"; //$NON-NLS-1$
+
+ private static final String WRONG_KEYSTORE_TYPE_ICON_PATH = "icons/keystore_incorrect_type.png";
+
+ private final PasswordProvider passwordProvider;
+
+ private boolean ignoreRefresh;
+
+ private boolean quiet;
+
+ private boolean skipNextReload = false;
+
+ private boolean typeVerified;
+
+ public KeyStoreNode(File path)
+ {
+ this.keyStoreFile = path;
+ passwordProvider = new PasswordProvider(keyStoreFile);
+ updateStatus();
+ }
+
+ public KeyStoreNode(File path, String type)
+ {
+ this.keyStoreFile = path;
+ this.type = type;
+ passwordProvider = new PasswordProvider(keyStoreFile);
+ updateStatus();
+ }
+
+ public KeyStoreNode(File keyStoreFile, KeyStore keyStore)
+ {
+ this(keyStoreFile);
+ this.keyStore = keyStore;
+ this.type = keyStore.getType();
+ }
+
+ @Override
+ public PasswordProvider getPasswordProvider()
+ {
+ return passwordProvider;
+ }
+
+ @Override
+ public String getKeyStorePassword(boolean promptPassword)
+ {
+ String password = null;
+ boolean keepTrying = true;
+
+ //keep asking password until user either enter the correct password or cancel the operation
+ while (keepTrying)
+ {
+ try
+ {
+ try
+ {
+ keepTrying = false;
+ password = getPasswordProvider().getKeyStorePassword(promptPassword);
+ if (password != null)
+ {
+ isPasswordValid(password);
+ }
+ }
+ catch (InvalidPasswordException e)
+ {
+ getPasswordProvider().deleteKeyStoreSavedPasswordNode();
+ password = null;
+ keepTrying = true;
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ password = null;
+ keepTrying = false;
+
+ StudioLogger.info(
+ this.getClass(),
+ CertificateManagerNLS.KeyStoreNode_CouldNotGetKeyStorePassword
+ + e.getLocalizedMessage());
+ }
+ }
+
+ return password;
+ }
+
+ /**
+ * @return the path
+ */
+ @Override
+ public File getFile()
+ {
+ return keyStoreFile;
+ }
+
+ @Override
+ public KeyStore getKeyStore() throws KeyStoreManagerException
+ {
+ return getKeyStore(true);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore#
+ * getKeyStore()
+ */
+ public KeyStore getKeyStore(boolean load) throws KeyStoreManagerException
+ {
+ if (keyStore == null)
+ {
+ boolean tryAgain = false;
+ boolean useSavedPass = true;
+ String password = null;
+ do
+ {
+ if (tryAgain)
+ {
+ useSavedPass = false;
+ }
+ password = passwordProvider.getKeyStorePassword(true, useSavedPass);
+ tryAgain = false;
+ if (password != null)
+ {
+ try
+ {
+ keyStore = loadKeystore(password.toCharArray());
+ setTooltip(null);
+ if (load)
+ {
+ loadEntries();
+ }
+ }
+ catch (InvalidPasswordException e)
+ {
+ tryAgain = true;
+ }
+ }
+ else
+ {
+ setTooltip(CertificateManagerNLS.KeyStoreNode_CouldNotLoadKeystore_Tooltip);
+ }
+ }
+ while (tryAgain);
+ }
+
+ return keyStore;
+ }
+
+ public KeyStore getKeyStore(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ if ((keyStore == null) && (password != null))
+ {
+ keyStore = loadKeystore(password.toCharArray());
+ loadEntries();
+ }
+ else
+ {
+ //just check if given password is valid for this keystore
+ isPasswordValid(password);
+ }
+
+ return keyStore;
+ }
+
+ @Override
+ public boolean isPasswordValid(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ KeyStore myKeyStore = null;
+ if (password != null)
+ {
+ myKeyStore = loadKeystore(password.toCharArray());
+ }
+ else
+ {
+ throw new InvalidPasswordException(CertificateManagerNLS.KeyStoreNode_Password_NotNull);
+ }
+
+ return myKeyStore != null;
+ }
+
+ protected KeyStore loadKeystore(char[] password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ KeyStore keyStore = null;
+ setNodeStatus(Status.OK_STATUS);
+ setTooltip(null);
+ try
+ {
+ if (!typeVerified && type.equalsIgnoreCase("jceks")) //$NON-NLS-1$
+ {
+ //Try to load this as JKS.
+ keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, password, "JKS"); //$NON-NLS-1$
+ if (keyStore != null)
+ {
+ //Keystore type is actually wrong, it's a jks keystore.
+ EclipseUtils.showWarningDialog(
+ CertificateManagerNLS.KeyStoreNode_Wrong_KeystoreType_Title, NLS.bind(
+ CertificateManagerNLS.KeyStoreNode_Wrong_KeystoreType_Message,
+ getName()));
+ setType("JKS"); //$NON-NLS-1$
+ typeVerified = true;
+ }
+ }
+ }
+ catch (KeyStoreManagerException keyStoreManagerException)
+ {
+ //Do nothing, let's try with the correct type.
+ }
+ catch (InvalidPasswordException invalidPasswordException)
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_InvalidPassword));
+ throw invalidPasswordException;
+ }
+
+ try
+ {
+ keyStore = KeyStoreUtils.loadKeystore(keyStoreFile, password, type);
+ setNodeStatus(Status.OK_STATUS);
+ }
+ catch (KeyStoreManagerException keyStoreManagerException)
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ IKeyStore.WRONG_KEYSTORE_TYPE_ERROR_CODE,
+ CertificateManagerNLS.KeyStoreNode_KeystoreTypeWrong_NodeStatus, null));
+ throw keyStoreManagerException;
+ }
+ catch (InvalidPasswordException invalidPasswordException)
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_InvalidPassword));
+ throw invalidPasswordException;
+ }
+ return keyStore;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((keyStoreFile == null) ? 0 : keyStoreFile.hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (obj == null)
+ {
+ return false;
+ }
+ if (!(obj instanceof KeyStoreNode))
+ {
+ return false;
+ }
+ KeyStoreNode other = (KeyStoreNode) obj;
+ if (keyStoreFile == null)
+ {
+ if (other.keyStoreFile != null)
+ {
+ return false;
+ }
+ }
+ else if (!keyStoreFile.equals(other.keyStoreFile))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString()
+ {
+ return getName() + " - ( " + getId() + " )"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public void refresh() throws KeyStoreManagerException
+ {
+ if (!ignoreRefresh)
+ {
+ if (!skipNextReload)
+ {
+ keyStore = null;
+ skipNextReload = false;
+ }
+ entries.clear();
+ updateStatus();
+ if (getNodeStatus().isOK())
+ {
+ quiet = true;
+ loadEntries();
+ quiet = false;
+ passwordProvider.cleanModel(new ArrayList<String>(entries.keySet()));
+ }
+ }
+ else
+ {
+ setIgnoreRefresh(false);
+ }
+ }
+
+ private void setIgnoreRefresh(boolean ignoreRefresh)
+ {
+ this.ignoreRefresh = ignoreRefresh;
+ }
+
+ @Override
+ public String getId()
+ {
+ return keyStoreFile.getAbsolutePath();
+ }
+
+ @Override
+ public String getName()
+ {
+ return keyStoreFile.getName();
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ ImageDescriptor descr = null;
+ if (!isStoreTypeCorrect())
+ {
+ //wrong keystore type
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WRONG_KEYSTORE_TYPE_ICON_PATH);
+ }
+ else if (isPasswordSaved())
+ {
+ //saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID,
+ KEYSTORE_SAVED_PASSWORD_ICON_PATH);
+ }
+ else
+ {
+ //non saved password
+ descr =
+ CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID,
+ KEYSTORE_NONSAVED_PASSWORD_ICON_PATH);
+ }
+ return descr;
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return false;
+ }
+
+ @Override
+ public List<ITreeNode> getChildren() throws KeyStoreManagerException
+ {
+ ArrayList<ITreeNode> children = new ArrayList<ITreeNode>(entries.values());
+ return children;
+ }
+
+ private void loadEntries() throws KeyStoreManagerException
+ {
+ if (entries.size() == 1)
+ {
+ ITreeNode entryNode = entries.get(DUMMY_NODE); //$NON-NLS-1$
+ if (entryNode != null)
+ {
+ entries.remove(DUMMY_NODE); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ }
+ }
+ entries.clear();
+ KeyStore keyStore = getKeyStore(false);
+ if (keyStore != null)
+ {
+ Enumeration<String> aliases;
+ try
+ {
+ aliases = keyStore.aliases();
+ }
+ catch (KeyStoreException e)
+ {
+ throw new KeyStoreManagerException(CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeyStoreModel_Error_GettingAliasesFromKeystore,
+ getName()), e);
+ }
+
+ List<String> keyPairEntries = new ArrayList<String>();
+ while (aliases.hasMoreElements())
+ {
+ String alias = aliases.nextElement();
+ EntryNode keyStoreEntry = new EntryNode(this, alias);
+ if (!keyStoreEntry.isKeyPairEntry())
+ {
+ //we will not support key pairs
+ entries.put(alias, keyStoreEntry);
+ }
+ else
+ {
+ //is key pair
+ keyPairEntries.add(alias);
+ String msg =
+ CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeyStoreNode_KeyPairNotMapped_LogMessage,
+ alias);
+ StudioLogger.debug(msg);
+ }
+ }
+ if ((keyPairEntries != null) && !keyPairEntries.isEmpty())
+ {
+ //found key pairs
+ DialogWithToggleUtils.showInformation(WARN_ABOUT_UNSUPPORTED_ENTRIES_PREFERENCE,
+ CertificateManagerNLS.KeyStoreNode_KeyPairNotMapped_Title,
+ CertificateManagerNLS.KeyStoreNode_KeyPairNotMapped_Message);
+ }
+
+ if (entries.isEmpty())
+ {
+ entries.put(DUMMY_NODE, new EntryDummyNode(this)); //$NON-NLS-1$
+ }
+ }
+ else
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_UseRefresh_StatusNode));
+ }
+ }
+
+ private void updateStatus()
+ {
+ setNodeStatus(Status.OK_STATUS);
+ if (!keyStoreFile.exists())
+ {
+ setNodeStatus(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID,
+ CertificateManagerNLS.KeyStoreNode_KeystoreFileNotFound));
+ }
+ }
+
+ @Override
+ public void addChild(ITreeNode newChild)
+ {
+ if (entries.size() == 1)
+ {
+ ITreeNode entryNode = entries.get(DUMMY_NODE); //$NON-NLS-1$
+ if (entryNode != null)
+ {
+ entries.remove(DUMMY_NODE); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ }
+ }
+ if ((newChild instanceof IKeyStoreEntry) || (newChild instanceof EntryDummyNode))
+ {
+ EntryNode entryNode = (EntryNode) newChild;
+ String alias = entryNode.getAlias();
+ entries.put(alias, entryNode);
+ if (!quiet && !(newChild instanceof EntryDummyNode))
+ {
+ KeyStoreModelEventManager.getInstance().fireEvent(newChild, EventType.ADD);
+ }
+ }
+ }
+
+ /**
+ * @return the lastBackupDate
+ */
+ @Override
+ public Date getLastBackupDate()
+ {
+ return lastBackupDate;
+ }
+
+ /**
+ * @param lastBackupDate
+ * the lastBackupDate to set
+ */
+ @Override
+ public void setLastBackupDate(Date lastBackupDate)
+ {
+ this.lastBackupDate = lastBackupDate;
+ try
+ {
+ KeyStoreManager.getInstance().setBackupDate(this, lastBackupDate);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Could not set backup date for keystore");
+ }
+ KeyStoreModelEventManager.getInstance().fireEvent(this, EventType.UPDATE);
+ }
+
+ /**
+ * @return the type
+ */
+ @Override
+ public String getType()
+ {
+ return type != null ? type : KeyStore.getDefaultType().toUpperCase();
+ }
+
+ /**
+ * @param type
+ * the type to set
+ * @throws KeyStoreManagerException
+ */
+ @Override
+ public void setType(String type) throws KeyStoreManagerException
+ {
+ this.type = type;
+ KeyStoreManager.getInstance().updateKeyStoreType(this);
+ }
+
+ @Override
+ public List<IKeyStoreEntry> getEntries(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ getKeyStore(password);
+ ArrayList<IKeyStoreEntry> children = new ArrayList<IKeyStoreEntry>(entries.size());
+ for (ITreeNode treeNode : entries.values())
+ {
+ if (treeNode instanceof IKeyStoreEntry)
+ {
+ children.add((IKeyStoreEntry) treeNode);
+ }
+ }
+ return children;
+ }
+
+ @Override
+ public IKeyStoreEntry getEntry(String alias, String keystorePassword)
+ throws KeyStoreManagerException, InvalidPasswordException
+ {
+ IKeyStoreEntry result = null;
+ for (IKeyStoreEntry entry : getEntries(keystorePassword))
+ {
+ if (entry.getAlias().equalsIgnoreCase(alias))
+ {
+ result = entry;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<String> getAliases(String password) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ getKeyStore(password);
+
+ ArrayList<String> children = new ArrayList<String>(entries.size());
+ for (ITreeNode treeNode : entries.values())
+ {
+ if (treeNode instanceof IKeyStoreEntry)
+ {
+ children.add(((IKeyStoreEntry) treeNode).getAlias());
+ }
+ }
+ return children;
+ }
+
+ @Override
+ public void removeKey(String alias) throws KeyStoreManagerException
+ {
+ String password = passwordProvider.getKeyStorePassword(true, true);
+ if (password != null)
+ {
+ KeyStoreUtils.deleteEntry(keyStore, password.toCharArray(), keyStoreFile, alias);
+ try
+ {
+ forceReload(password.toCharArray(), false);
+ }
+ catch (InvalidPasswordException e)
+ {
+ //Should never happen.
+ StudioLogger.debug("Could reload ks after removing entry, invalid password"); //$NON-NLS-1$
+ }
+
+ ITreeNode entryNode = entries.remove(alias);
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ if (entries.isEmpty())
+ {
+ EntryDummyNode entryDummyNode = new EntryDummyNode(this);
+ entries.put(DUMMY_NODE, entryDummyNode); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryDummyNode, EventType.ADD);
+ }
+ }
+ else
+ {
+ // password not found
+ throw new KeyStoreManagerException(
+ CertificateManagerNLS.KeyStoreNode_NotFoundOrIncorrectPasswordToDeleteEntry
+ + alias);
+ }
+
+ }
+
+ @Override
+ public void removeKeys(List<String> aliases) throws KeyStoreManagerException
+ {
+ String password = passwordProvider.getKeyStorePassword(true, true);
+ if (password != null)
+ {
+ for (String alias : aliases)
+ {
+ KeyStoreUtils.deleteEntry(keyStore, password.toCharArray(), keyStoreFile, alias);
+
+ ITreeNode entryNode = entries.remove(alias);
+ KeyStoreModelEventManager.getInstance().fireEvent(entryNode, EventType.REMOVE);
+ }
+ try
+ {
+ forceReload(password.toCharArray(), false);
+ }
+ catch (InvalidPasswordException e)
+ {
+ //Should never happen.
+ StudioLogger.debug("Could reload ks after removing entry, invalid password"); //$NON-NLS-1$
+ }
+ if (entries.isEmpty())
+ {
+ EntryDummyNode entryDummyNode = new EntryDummyNode(this);
+ entries.put(DUMMY_NODE, entryDummyNode); //$NON-NLS-1$
+ KeyStoreModelEventManager.getInstance().fireEvent(entryDummyNode, EventType.ADD);
+ }
+ }
+ else
+ {
+ // password not found
+ throw new KeyStoreManagerException(
+ CertificateManagerNLS.KeyStoreNode_IncorrectPasswordToDeleteEntries_Error);
+ }
+
+ }
+
+ @Override
+ public boolean testAttribute(Object target, String name, String value)
+ {
+ boolean result = super.testAttribute(target, name, value);
+ if (name.equals(PROP_NAME_NODE_STATUS))
+ {
+ if (value.equals(PROP_VALUE_NODE_STATUS_ERROR))
+ {
+ if (!isStoreTypeCorrect())
+ {
+ //when store type is incorrect the icon is changed, not decorated.
+ result = false;
+ }
+ else if (!keyStoreFile.exists())
+ {
+ // keystore not found
+ result = true;
+ setTooltip(CertificateManagerNLS.KeyStoreNode_ErrorKeystoreNotFound);
+ }
+ }
+ else if (value.equals(PROP_VALUE_NODE_STATUS_KEYSTORE_TYPE_OK))
+ {
+ result = isStoreTypeCorrect();
+ }
+
+ }
+ return result;
+ }
+
+ @Override
+ public void forceReload(char[] password, boolean updateUi) throws KeyStoreManagerException,
+ InvalidPasswordException
+ {
+ keyStore = loadKeystore(password);
+
+ if (updateUi)
+ {
+ skipNextReload = true;
+ KeyStoreModelEventManager.getInstance().fireEvent(this, EventType.REFRESH);
+ }
+ }
+
+ @Override
+ protected boolean isPasswordSaved()
+ {
+ PasswordProvider pp = new PasswordProvider(getFile());
+ return pp.isPasswordSaved();
+ }
+
+ protected boolean isStoreTypeCorrect()
+ {
+ return getNodeStatus().getCode() != WRONG_KEYSTORE_TYPE_ERROR_CODE;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java new file mode 100644 index 0000000..5c07df7 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/KeyStoreRootNode.java @@ -0,0 +1,126 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent;
+import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Node that is the parent of keyStores (root node of {@link KeystoreManagerView})
+ */
+public class KeyStoreRootNode extends AbstractTreeNode
+{
+ //Map from absolute file path to KeyStoreModel
+ private final List<ITreeNode> keyStores = new ArrayList<ITreeNode>();
+
+ /**
+ * Adds keystore to root node of the tree
+ * @param keyStoreModel
+ * @throws KeyStoreManagerException if the keystore is already listed in the tree
+ */
+ public void addKeyStoreNode(KeyStoreNode keyStoreModel) throws KeyStoreManagerException
+ {
+ if (!keyStores.contains(keyStoreModel))
+ {
+ keyStores.add(keyStoreModel);
+ keyStoreModel.setParent(this);
+
+ KeyStoreModelEventManager.getInstance().fireEvent(keyStoreModel,
+ KeyStoreModelEvent.EventType.ADD);
+ }
+ else
+ {
+ //error - notify
+ throw new KeyStoreManagerException(CertificateManagerNLS.bind(
+ CertificateManagerNLS.KeyStoreRootNode_Error_AlreadyMappedKeystorePath,
+ keyStoreModel.getFile().getAbsolutePath()));
+ }
+ }
+
+ public void removeKeyStore(KeyStoreNode keyStoreModel)
+ {
+ keyStores.remove(keyStoreModel);
+ KeyStoreModelEventManager.getInstance().fireEvent(keyStoreModel,
+ KeyStoreModelEvent.EventType.REMOVE);
+ File keysToreFile = keyStoreModel.getFile();
+
+ PasswordProvider password = new PasswordProvider(keysToreFile);
+
+ try
+ {
+ password.deleteKeyStoreSavedPasswordNode();
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+
+ }
+
+ @Override
+ public void refresh()
+ {
+ //Not necessary, root nod can't be refreshed
+ }
+
+ @Override
+ public String getId()
+ {
+ return ""; //not necessary - root node //$NON-NLS-1$
+ }
+
+ @Override
+ public String getName()
+ {
+ return ""; //not necessary - root node //$NON-NLS-1$
+ }
+
+ @Override
+ public ImageDescriptor getIcon()
+ {
+ return null; //not necessary - root node
+ }
+
+ @Override
+ public boolean isLeaf()
+ {
+ return false; //root node
+ }
+
+ @Override
+ public ITreeNode getParent()
+ {
+ return null; //invisible node
+ }
+
+ @Override
+ public List<ITreeNode> getChildren()
+ {
+ return new ArrayList<ITreeNode>(keyStores);
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java new file mode 100644 index 0000000..d4493f6 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/model/SigningAndKeysModelManager.java @@ -0,0 +1,148 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.model;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.BackwardKeystoreManager;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.views.KeystoreManagerView;
+
+/**
+ * Provides services to map and unmap keystores.
+ * Also get access to the root node and populates on first access (based on {@link KeyStoreManager}).
+ *
+ */
+public class SigningAndKeysModelManager
+{
+ private KeyStoreRootNode keyStoresRootNode = new KeyStoreRootNode();
+
+ private static SigningAndKeysModelManager _instance = null;
+
+ private SigningAndKeysModelManager()
+ {
+ }
+
+ public static synchronized SigningAndKeysModelManager getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new SigningAndKeysModelManager();
+ _instance.populateKeyStoreRootNode();
+ }
+ return _instance;
+ }
+
+ public File[] getKeystoreFiles()
+ {
+ List<ITreeNode> nodes = keyStoresRootNode.getChildren();
+
+ File[] files = new File[nodes.size()];
+ int i = 0;
+ for (ITreeNode node : nodes)
+ {
+
+ File file = ((KeyStoreNode) node).getFile();
+ files[i++] = file;
+ }
+
+ return files;
+ }
+
+ public KeyStoreRootNode populateKeyStoreRootNode()
+ {
+ try
+ {
+ List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
+ if (keyStores != null)
+ {
+ if (keyStores.size() > 0)
+ {
+ //there are items mapped on persistence
+ for (IKeyStore keyStore : keyStores)
+ {
+ if (keyStore instanceof KeyStoreNode)
+ {
+ keyStoresRootNode.addKeyStoreNode((KeyStoreNode) keyStore);
+ }
+ }
+ }
+ else
+ {
+ //we do not have any item mapped in persistence
+ //try to import from old Motodev keystore
+ //(probably it is the first time user is trying to use the view)
+ BackwardKeystoreManager backwardKeystoreManager = new BackwardKeystoreManager();
+ backwardKeystoreManager.mapOldKeystore();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(KeystoreManagerView.class, e.getMessage(), e);
+ EclipseUtils
+ .showErrorDialog(
+ CertificateManagerNLS.KeystoreManagerView_ErrorLoadingMappedKeystoresFromPersistence,
+ e.getMessage());
+ }
+
+ return keyStoresRootNode;
+ }
+
+ public void unmapKeyStore(KeyStoreNode keyStoreNode)
+ {
+ keyStoresRootNode.removeKeyStore(keyStoreNode);
+ try
+ {
+ File file = keyStoreNode.getFile();
+ PasswordProvider passwordProvider = new PasswordProvider(file);
+ passwordProvider.deleteKeyStoreSavedPasswordNode();
+ KeyStoreManager.getInstance().removeKeyStore(keyStoreNode);
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showErrorDialog("Error unmapping KeyStore", NLS.bind(
+ "Could not unmap the keystore file {0}", keyStoreNode.getFile()), new Status(
+ IStatus.ERROR, "Error unmapping KeyStore",
+ CertificateManagerActivator.PLUGIN_ID, e));
+ }
+ }
+
+ public void mapKeyStore(KeyStoreNode keyStoreNode) throws KeyStoreManagerException
+ {
+ keyStoresRootNode.addKeyStoreNode(keyStoreNode);
+ KeyStoreManager.getInstance().addKeyStore(keyStoreNode);
+ }
+
+ /**
+ * @return the keyStoresRootNode (populated through {@link SigningAndKeysModelManager#getInstance(), in the first access}
+ */
+ public KeyStoreRootNode getKeyStoresRootNode()
+ {
+ return keyStoresRootNode;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java new file mode 100644 index 0000000..ed911c8 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/ExpiresInColumnLabelProvider.java @@ -0,0 +1,55 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.tree;
+
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.Locale;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry;
+
+public class ExpiresInColumnLabelProvider extends ColumnLabelProvider
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof IKeyStoreEntry)
+ {
+ EntryNode keyStoreEntry = (EntryNode) element;
+ X509Certificate x509Certificate = keyStoreEntry.getX509Certificate();
+ //Android certificate
+ return getExpiresInDate(x509Certificate);
+ }
+ return "";
+ }
+
+ /**
+ * Returns the date where the certificate expires
+ * @param cert
+ * @return
+ */
+ private String getExpiresInDate(X509Certificate x509Certificate)
+ {
+ return (x509Certificate != null) ? DateFormat.getDateInstance(DateFormat.MEDIUM,
+ Locale.getDefault()).format(x509Certificate.getNotAfter()) : "";
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java new file mode 100644 index 0000000..34a08a6 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/KeystoreManagerTreeContentProvider.java @@ -0,0 +1,132 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.tree;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.ILazyTreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+public class KeystoreManagerTreeContentProvider implements ILazyTreeContentProvider
+{
+
+ private final TreeViewer treeViewer;
+
+ public KeystoreManagerTreeContentProvider(TreeViewer viewer)
+ {
+ this.treeViewer = viewer;
+ }
+
+ @Override
+ public void dispose()
+ {
+ //Nothing
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //Nothing
+ }
+
+ @Override
+ public void updateElement(Object parent, int index)
+ {
+ if (parent instanceof ITreeNode)
+ {
+ ITreeNode parentNode = (ITreeNode) parent;
+ ITreeNode child = null;
+ try
+ {
+ List<ITreeNode> children = parentNode.getChildren();
+ if (!children.isEmpty())
+ {
+ child = children.get(index);
+ }
+ }
+ catch (Exception e)
+ {
+ child = null;
+ }
+
+ if (child != null)
+ {
+ treeViewer.replace(parent, index, child);
+ try
+ {
+ if (child.getChildren().isEmpty())
+ {
+ treeViewer.setHasChildren(child, !child.isLeaf());
+ }
+ else
+ {
+ treeViewer.setChildCount(child, child.getChildren().size());
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error("Error while accessing keystore manager. " + e.getMessage());
+ }
+ }
+ }
+
+ }
+
+ @Override
+ public void updateChildCount(Object element, int currentChildCount)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) element;
+ int childCount = 0;
+ try
+ {
+ treeNode.refresh();
+ List<ITreeNode> children = treeNode.getChildren();
+ if (!children.isEmpty())
+ {
+ childCount = children.size();
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ StudioLogger.error(e.getMessage());
+ }
+
+ if (childCount != currentChildCount)
+ {
+ treeViewer.setChildCount(element, childCount);
+ }
+ }
+ }
+
+ @Override
+ public ITreeNode getParent(Object element)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) element;
+ return treeNode.getParent();
+ }
+ return null;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java new file mode 100644 index 0000000..8fc4877 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/LastBackupDateColumnLabelProvider.java @@ -0,0 +1,46 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.tree;
+
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class LastBackupDateColumnLabelProvider extends ColumnLabelProvider
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof IKeyStore)
+ {
+ IKeyStore iKeyStore = (IKeyStore) element;
+
+ if (iKeyStore.getLastBackupDate() != null)
+ {
+ SimpleDateFormat formatter =
+ new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.getDefault());
+ return formatter.format(iKeyStore.getLastBackupDate());
+ }
+ }
+ return "";
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java new file mode 100644 index 0000000..5377ab4 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/NameAliasColumnLabelProvider.java @@ -0,0 +1,135 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.tree;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
+
+public class NameAliasColumnLabelProvider extends ColumnLabelProvider
+{
+ final IDecoratorManager decorator;
+
+ public NameAliasColumnLabelProvider()
+ {
+ decorator = PlatformUI.getWorkbench().getDecoratorManager();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object)
+ */
+ @Override
+ public Image getImage(Object element)
+ {
+ Image result = null;
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode node = (ITreeNode) element;
+ Image defaultImage = null;
+ if (node.getIcon() != null)
+ {
+ defaultImage = node.getIcon().createImage();
+ result = decorator.decorateImage(defaultImage, element);
+ }
+ if (result == null)
+ {
+ result = defaultImage;
+ }
+ }
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode node = (ITreeNode) element;
+ return node.getName();
+ }
+ return ""; //other items do not need to show this column with data
+ }
+
+ @Override
+ public void update(ViewerCell cell)
+ {
+ Object cellElement = cell.getElement();
+ cell.setText(getText(cellElement));
+ if (getImage(cellElement) != null)
+ {
+ cell.setImage(getImage(cellElement));
+ }
+ }
+
+ @Override
+ public String getToolTipText(Object element)
+ {
+ if (element instanceof ITreeNode)
+ {
+ ITreeNode treeNode = (ITreeNode) element;
+
+ return treeNode.getTooltip();
+ }
+ return super.getToolTipText(element);
+ }
+
+ @Override
+ public int getToolTipTimeDisplayed(Object object)
+ {
+ return 4000;
+ }
+
+ @Override
+ public int getToolTipDisplayDelayTime(Object object)
+ {
+ return 500;
+ }
+
+ @Override
+ public Point getToolTipShift(Object object)
+ {
+ return new Point(5, 5);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ decorator.addListener(listener);
+ super.addListener(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
+ */
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ decorator.removeListener(listener);
+ super.removeListener(listener);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java new file mode 100644 index 0000000..32fa02b --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/PathColumnLabelProvider.java @@ -0,0 +1,37 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.tree;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+public class PathColumnLabelProvider extends ColumnLabelProvider
+{
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof KeyStoreNode)
+ {
+ KeyStoreNode keyStoreModel = (KeyStoreNode) element;
+ return keyStoreModel.getFile().getAbsolutePath();
+ }
+ return ""; //other items do not need to show this column with data
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java new file mode 100644 index 0000000..a8a9fd4 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/tree/TypeColumnLabelProvider.java @@ -0,0 +1,39 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.tree;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+public class TypeColumnLabelProvider extends ColumnLabelProvider
+{
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element)
+ {
+ if (element instanceof IKeyStore)
+ {
+ IKeyStore iKeyStore = (IKeyStore) element;
+ return iKeyStore.getType();
+ }
+ return ""; //other items do not need to show this column with data
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java new file mode 100644 index 0000000..f949f0f --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizard.java @@ -0,0 +1,107 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.wizards.BaseWizard;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+/**
+ * Wizard to create an Android key.
+ */
+public class CreateKeyWizard extends BaseWizard
+{
+
+ private static final String WIZARD_BANNER = "icons/wizban/create_key_wiz.png"; //$NON-NLS-1$
+
+ private boolean success = false;
+
+ /**
+ * Wizard page to allow the user to inform the key pair alias and
+ * distinguished name.
+ */
+ private final CreateKeyWizardPage createkeyWizardPage;
+
+ public CreateKeyWizard(IKeyStore keystore)
+ {
+ setupWizardUi();
+ createkeyWizardPage = new CreateKeyWizardPage(keystore);
+ }
+
+ public CreateKeyWizard(IKeyStore keystore, String keystorePassword,
+ IJobChangeListener createKeyJobListener)
+ {
+ setupWizardUi();
+ createkeyWizardPage =
+ new CreateKeyWizardPage(keystore, keystorePassword, createKeyJobListener);
+ }
+
+ private void setupWizardUi()
+ {
+ setWindowTitle(CertificateManagerNLS.CreateSelfSignedCertificateWizardPage_Title);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has the same help as its single page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), CreateKeyWizardPage.CREATE_SELF_SIGNED_CERTIFICATE_HELP_ID);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @seecom.motorola.studio.android.wizards.BaseWizard#
+ * doPerformFinish()
+ */
+ @Override
+ protected boolean doPerformFinish()
+ {
+ success = createkeyWizardPage.createKey();
+ return success;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ super.addPages();
+ addPage(createkeyWizardPage);
+ }
+
+ /**
+ * Returns the alias of the just created key or null otherwise.
+ */
+ public String getAlias()
+ {
+ return success ? createkeyWizardPage.getTrueAlias() : null;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java new file mode 100644 index 0000000..286cbeb --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeyWizardPage.java @@ -0,0 +1,284 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.jface.wizard.IWizard;
+
+import com.motorola.studio.android.wizards.BaseWizardPage;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.job.CreateKeyJob;
+import com.motorolamobility.studio.android.certmanager.ui.composite.NewKeyBlock;
+import com.motorolamobility.studio.android.certmanager.ui.model.CertificateDetailsInfo;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+
+/**
+ * Wizard page to create an Android key.
+ */
+public class CreateKeyWizardPage extends BaseWizardPage
+{
+ private IKeyStore keystore = null;
+
+ private String alias = null;
+
+ private String keyStorePass;
+
+ public static final String CREATE_SELF_SIGNED_CERTIFICATE_HELP_ID =
+ CertificateManagerActivator.PLUGIN_ID + ".create-self-cert";
+
+ private IJobChangeListener createKeyJobListener = null;
+
+ /**
+ * The default constructor.
+ */
+ public CreateKeyWizardPage(IKeyStore keystore)
+ {
+ super(new NewKeyBlock(), CertificateManagerNLS.CreateSelfSignedCertificateWizardPage_Title,
+ CertificateManagerNLS.CreateSelfSignedCertificateWizardPage_Description,
+ CREATE_SELF_SIGNED_CERTIFICATE_HELP_ID); //$NON-NLS-2$
+ ((NewKeyBlock) block).setBaseWizardPage(this);
+ this.keystore = keystore;
+ }
+
+ public CreateKeyWizardPage(IKeyStore keystore, String keystorePassword,
+ IJobChangeListener createKeyJobListener)
+ {
+ this(keystore);
+ setKeyStorePass(keystorePassword);
+ this.createKeyJobListener = createKeyJobListener;
+ }
+
+ /**
+ * Obtains the key pair alias defined by user.
+ *
+ * @return The key pair alias.
+ */
+ public String getAlias()
+ {
+ return ((NewKeyBlock) block).getAlias();
+ }
+
+ /**
+ * Obtains the common name defined by user.
+ *
+ * @return The common name.
+ */
+ public String getCommonName()
+ {
+ return ((NewKeyBlock) block).getCommonName();
+ }
+
+ /**
+ * Obtains the organization defined by user.
+ *
+ * @return The organization.
+ */
+ public String getOrganization()
+ {
+ return ((NewKeyBlock) block).getOrganization();
+ }
+
+ /**
+ * Obtains the organization unit defined by user.
+ *
+ * @return The organization unit.
+ */
+ public String getOrganizationUnit()
+ {
+ return ((NewKeyBlock) block).getOrganizationUnit();
+ }
+
+ /**
+ * Obtains the locality defined by user.
+ *
+ * @return The locality.
+ */
+ public String getLocality()
+ {
+ return ((NewKeyBlock) block).getLocality();
+ }
+
+ /**
+ * Obtains the state defined by user.
+ *
+ * @return The state.
+ */
+ public String getState()
+ {
+ return ((NewKeyBlock) block).getState();
+ }
+
+ /**
+ * Obtains the country defined by user.
+ *
+ * @return The country.
+ */
+ public String getCountry()
+ {
+ return ((NewKeyBlock) block).getCountry();
+ }
+
+ /**
+ * Obtains the validity defined by user.
+ *
+ * @return The validity.
+ */
+ public String getValidity()
+ {
+ return ((NewKeyBlock) block).getValidity();
+ }
+
+ public String getEntryPassword()
+ {
+ return ((NewKeyBlock) block).getKeyPassword();
+ }
+
+ public String getEntryConfirmPassword()
+ {
+ return ((NewKeyBlock) block).getKeyConfirmPassword();
+ }
+
+ public boolean needToSaveKeyEntryPassword()
+ {
+ return ((NewKeyBlock) block).needToSaveKeyPassword();
+ }
+
+ public boolean createKey()
+ {
+ boolean successfullyCreated = true;
+ alias = getAlias();
+
+ if (isPageCompleteWithAllFieldsBlank())
+ {
+ successfullyCreated = true;
+ }
+ else
+ {
+ final CertificateDetailsInfo certificateDetailsInfo =
+ new CertificateDetailsInfo(alias, getCommonName(), getOrganization(),
+ getOrganizationUnit(), getLocality(), getCountry(), getState(),
+ getValidity(), getEntryPassword());
+ CreateKeyJob createKeyJob =
+ new CreateKeyJob("Create key job", (NewKeyBlock) block, certificateDetailsInfo,
+ keystore, keyStorePass);
+
+ if (createKeyJobListener != null)
+ {
+ createKeyJob.addJobChangeListener(createKeyJobListener);
+ }
+ createKeyJob.schedule();
+
+ successfullyCreated = true;
+ }
+
+ return successfullyCreated;
+ }
+
+ /**
+ * @param keystoreNode
+ */
+ public void setKeyStore(IKeyStore keystoreNode)
+ {
+ this.keystore = keystoreNode;
+ }
+
+ /*
+ * If all fields are blank and this page is under CreateKeystoreWizard context,
+ * then if all fields are blank the page is considered complete and no keypair will be created.
+ */
+ public boolean isPageCompleteWithAllFieldsBlank()
+ {
+ boolean result = false;
+ IWizard wizardContext = getWizard();
+
+ //in the context of CreateKeyStoreWizard and if this is NOT the current page, then allow all fields blank
+ //be a valid complete page
+ if ((wizardContext instanceof CreateKeystoreWizard) && !isCurrentPage()
+ && areAllFieldsBlank())
+ {
+ result = true;
+ }
+
+ return result;
+ }
+
+ /*
+ * return true if all fields are blank
+ */
+ private boolean areAllFieldsBlank()
+ {
+ boolean result = false;
+ if (getAlias().isEmpty() && getCommonName().isEmpty() && getOrganization().isEmpty()
+ && getOrganizationUnit().isEmpty() && getLocality().isEmpty()
+ && getState().isEmpty() && getCountry().isEmpty() && getEntryPassword().isEmpty()
+ && getEntryConfirmPassword().isEmpty())
+ {
+ result = true;
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.jface.wizard.WizardPage#isPageComplete()
+ */
+ @Override
+ public boolean isPageComplete()
+ {
+ if (this.block == null)
+ {
+ return true;
+ }
+ return this.block.isPageComplete() || isPageCompleteWithAllFieldsBlank();
+ }
+
+ /**
+ * This method just works.
+ * @return
+ */
+ public String getTrueAlias()
+ {
+ return alias;
+ }
+
+ public void setKeyStorePass(String password)
+ {
+ this.keyStorePass = password;
+ }
+
+ /**
+ * @return the keystore
+ */
+ public IKeyStore getKeystore()
+ {
+ return keystore;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.DialogPage#setVisible(boolean)
+ */
+ @Override
+ public void setVisible(boolean visible)
+ {
+ super.setVisible(visible);
+ if (visible)
+ {
+ ((NewKeyBlock) block).setFocus();
+ }
+
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java new file mode 100644 index 0000000..9630e66 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystorePage.java @@ -0,0 +1,672 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+public class CreateKeystorePage extends WizardPage
+{
+
+ private static final String CREATE_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".new_keystore"; //$NON-NLS-1$
+
+ private Text keystoreFilenameText;
+
+ private ComboViewer keystoreTypeComboViewer;
+
+ private Text keystorePasswordText;
+
+ private Text keystoreConfirmPasswordText;
+
+ private String keystorePassword;
+
+ private boolean initialValidation = true;
+
+ private boolean userChangedPasswordConfirmation = false;
+
+ private boolean userChangedPassword = false;
+
+ SelectionListener selectionListener = new SelectionListener()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ validatePage();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e)
+ {
+ //nothing to do...
+ }
+ };
+
+ private Button savePassword;
+
+ private Button useTypeAsExtensionCheckBox;
+
+ protected boolean useTypeAsExtensionCheckBoxPreviousState = true;
+
+ /**
+ * @param pageName
+ */
+ protected CreateKeystorePage(String pageName)
+ {
+ super(pageName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent)
+ {
+ Composite mainComposite = new Composite(parent, SWT.FILL);
+ mainComposite.setLayout(new GridLayout(3, false));
+ mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ setTitle(CertificateManagerNLS.CreateKeystorePage_CreateKeystore);
+ setMessage(CertificateManagerNLS.CreateKeystorePage_WizardDefaultMessage);
+
+ createFilenameSection(mainComposite);
+ createKeystoreTypeSection(mainComposite);
+ createFilenameExtensionSection(mainComposite);
+
+ setKeystoreFilenameExtension();
+
+ //LINE TO SEPARATE PASSWORD SECTION FROM KEYSTORE DETAILS SECTION
+ Label separator1 = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
+
+ createKeystorePasswordSection(mainComposite);
+ createConfirmPasswordSection(mainComposite);
+ createSavePasswordSection(mainComposite);
+
+ validatePage();
+
+ setControl(mainComposite);
+
+ //set help id for this page
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, CREATE_KEYSTORE_HELP_ID);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(mainComposite, CREATE_KEYSTORE_HELP_ID);
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createKeystoreTypeSection(Composite parent)
+ {
+ Label keystoreTypeLabel = new Label(parent, SWT.NONE);
+ keystoreTypeLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreTypeLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreType);
+
+ keystoreTypeComboViewer = new ComboViewer(parent, SWT.READ_ONLY);
+ keystoreTypeComboViewer.getCombo().setLayoutData(
+ new GridData(SWT.FILL, SWT.NONE, true, false, 1, 1));
+ keystoreTypeComboViewer.setContentProvider(new IStructuredContentProvider()
+ {
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ return ((List<String>) inputElement).toArray();
+ }
+ });
+ keystoreTypeComboViewer.setLabelProvider(new ILabelProvider()
+ {
+
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property)
+ {
+ return false;
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public String getText(Object element)
+ {
+ return (String) element;
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+ return null;
+ }
+ });
+
+ keystoreTypeComboViewer.setInput(KeyStoreManager.getInstance().getAvailableTypes());
+
+ keystoreTypeComboViewer.getCombo().addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ useTypeAsExtensionCheckBox.setEnabled(true);
+ useTypeAsExtensionCheckBox.setSelection(useTypeAsExtensionCheckBoxPreviousState);
+
+ if (useTypeAsExtensionCheckBox.getSelection())
+ {
+ setKeystoreFilenameExtension();
+ }
+ }
+ });
+
+ for (int i = 0; i < keystoreTypeComboViewer.getCombo().getItemCount(); i++)
+ {
+ if (keystoreTypeComboViewer.getCombo().getItem(i)
+ .compareToIgnoreCase(KeyStoreManager.getInstance().getDefaultType()) == 0)
+ {
+ keystoreTypeComboViewer.getCombo().select(i);
+ }
+ }
+
+ keystoreTypeComboViewer.getCombo().addModifyListener(new ModifyListener()
+ {
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ if (useTypeAsExtensionCheckBox != null)
+ {
+ useTypeAsExtensionCheckBox.setEnabled(false);
+ useTypeAsExtensionCheckBox.setSelection(false);
+ }
+ }
+ });
+
+ //fill the third column with a blank label
+ Label separator2 = new Label(parent, SWT.NONE);
+ separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ /**
+ * Set the extension of the keystore based on selected keystore type and the user's choice to use it or not as the extension.
+ * If the user typed a custom keystore type, then the filename extension is set to ".keystore".
+ * */
+ protected void setKeystoreFilenameExtension()
+ {
+ String keystoreFilename = keystoreFilenameText.getText();
+ String keystoreType = keystoreTypeComboViewer.getCombo().getText();
+
+ List<String> availableTypes = KeyStoreManager.getInstance().getAvailableTypes();
+ availableTypes
+ .add(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilenameExtension);
+
+ for (String availableType : availableTypes)
+ {
+ String availableTypeExtension = "." + availableType.toLowerCase(); //$NON-NLS-1$
+ if (keystoreFilename.endsWith(availableTypeExtension))
+ {
+ keystoreFilename =
+ keystoreFilename.substring(0, keystoreFilename.length()
+ - availableTypeExtension.length());
+ break;
+ }
+ }
+
+ keystoreFilenameText.setText(keystoreFilename + "." + keystoreType.toLowerCase()); //$NON-NLS-1$
+ }
+
+ private void createFilenameExtensionSection(Composite mainComposite)
+ {
+ useTypeAsExtensionCheckBox = new Button(mainComposite, SWT.CHECK);
+ useTypeAsExtensionCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 3, 1));
+ useTypeAsExtensionCheckBox
+ .setText(CertificateManagerNLS.CreateKeystorePage_UseKeystoreTypeAsExtension);
+ useTypeAsExtensionCheckBox.setSelection(true);
+
+ useTypeAsExtensionCheckBox.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ useTypeAsExtensionCheckBoxPreviousState = useTypeAsExtensionCheckBox.getSelection();
+ if (useTypeAsExtensionCheckBox.getSelection())
+ {
+ setKeystoreFilenameExtension();
+ }
+ }
+ });
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createSavePasswordSection(Composite mainComposite)
+ {
+ savePassword = new Button(mainComposite, SWT.CHECK);
+ savePassword.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ savePassword.setText(CertificateManagerNLS.CreateKeystorePage_SaveThisPassword);
+ savePassword.setSelection(false);
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createConfirmPasswordSection(Composite mainComposite)
+ {
+ Label keystoreConfirmPasswordLabel = new Label(mainComposite, SWT.NONE);
+ keystoreConfirmPasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
+ 1, 1));
+ keystoreConfirmPasswordLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystoreConfirmPasswordLabel);
+
+ keystoreConfirmPasswordText =
+ new Text(mainComposite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keystoreConfirmPasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+ 1, 1));
+ keystoreConfirmPasswordText.addSelectionListener(selectionListener);
+ keystoreConfirmPasswordText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ userChangedPasswordConfirmation = true;
+ validatePage();
+ }
+ });
+
+ //fill the third column with a blank label
+ Label separator2 = new Label(mainComposite, SWT.NONE);
+ separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createKeystorePasswordSection(Composite mainComposite)
+ {
+ Label keystorePasswordLabel = new Label(mainComposite, SWT.NONE);
+ keystorePasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystorePasswordLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystorePasswordLabel);
+
+ keystorePasswordText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keystorePasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keystorePasswordText.addSelectionListener(selectionListener);
+ keystorePasswordText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ keystorePassword = keystorePasswordText.getText();
+ userChangedPassword = true;
+ validatePage();
+ }
+ });
+
+ //fill the third column with a blank label
+ @SuppressWarnings("unused")
+ Label separator = new Label(mainComposite, SWT.NONE);
+ keystorePasswordLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ /**
+ * @param mainComposite
+ */
+ private void createFilenameSection(Composite mainComposite)
+ {
+ Label keystoreFilenameLabel = new Label(mainComposite, SWT.NONE);
+ keystoreFilenameLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreFilenameLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameLabel);
+
+ keystoreFilenameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
+ keystoreFilenameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keystoreFilenameText.setText(generateKeyStoreFilename());
+ keystoreFilenameText.addSelectionListener(selectionListener);
+ keystoreFilenameText.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ validatePage();
+ }
+ });
+
+ Button chooseLocation = new Button(mainComposite, SWT.PUSH);
+ chooseLocation.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
+ chooseLocation.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameBrowse);
+ chooseLocation.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ Shell shell = Display.getCurrent().getActiveShell();
+
+ FileDialog dialog = new FileDialog(shell, SWT.SAVE);
+
+ String keystoreFilenameStr = dialog.open();
+
+ if (keystoreFilenameStr != null)
+ {
+ keystoreFilenameText.setText(keystoreFilenameStr);
+ }
+ }
+ });
+ }
+
+ private void validatePage()
+ {
+ boolean pageComplete = true;
+
+ String errorMessage = null;
+
+ String message = CertificateManagerNLS.CreateKeystorePage_WizardDefaultMessage;
+
+ int messageType = IMessageProvider.NONE;
+
+ if (initialValidation == true)
+ {
+ //when the wizard opens, does not show any errors
+ pageComplete = false;
+ initialValidation = false;
+ }
+ else
+ {
+ //password text and confirmation password text must match
+ if (!keystorePasswordText.getText().equals(keystoreConfirmPasswordText.getText()))
+ {
+ //if the user hasn't started typing the confirmation password,
+ //then just show an info, instead of an error
+ if (userChangedPasswordConfirmation)
+ {
+ errorMessage = CertificateManagerNLS.CreateKeystorePage_PasswordDoesNotMatch;
+ pageComplete = false;
+ }
+ else
+ {
+ message = CertificateManagerNLS.CreateKeystorePage_ConfirmPasswordInfoMsg;
+ messageType = IMessageProvider.INFORMATION;
+ pageComplete = false;
+ }
+ }
+ //check password size according to keytool specification
+ if (keystorePasswordText.getText().length() < KeyStoreNode.KEYSTORE_PASSWORD_MIN_SIZE)
+ {
+ if (userChangedPassword)
+ {
+ errorMessage =
+ CertificateManagerNLS
+ .bind(CertificateManagerNLS.CreateKeystorePage_PasswordMinSizeMessage,
+ KeyStoreNode.KEYSTORE_PASSWORD_MIN_SIZE); //$NON-NLS-1$
+ pageComplete = false;
+ }
+ else
+ {
+ message = CertificateManagerNLS.CreateKeystorePage_SetPasswordInfoMsg;
+ messageType = IMessageProvider.INFORMATION;
+ pageComplete = false;
+ }
+ }
+
+ //check if store type is filled
+ if (keystoreTypeComboViewer.getCombo().getText().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.CreateKeystorePage_SetKeystoreType;
+ pageComplete = false;
+ }
+
+ //check if filename is valid
+ try
+ {
+ File keystoreFile = new File(keystoreFilenameText.getText().trim());
+ Path keystorePath = new Path(keystoreFilenameText.getText().trim());
+ if (!keystorePath.isValidPath(keystoreFile.getCanonicalPath()))
+ {
+ //throw the same exception as getCanonicalPath() in order to do not duplicate code
+ throw new IOException();
+ }
+ }
+ catch (IOException e)
+ {
+ errorMessage = CertificateManagerNLS.CreateKeystorePage_FilenameSyntaxError;
+ pageComplete = false;
+ }
+ if (keystoreFilenameText.getText().trim().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.ImportKeystorePage_FilenameCannotBeEmpty;
+ pageComplete = false;
+ }
+ }
+
+ setMessage(message, messageType);
+ setErrorMessage(errorMessage);
+ setPageComplete(pageComplete);
+ }
+
+ /**
+ * Generate a valid filename for a new keystore.
+ * The file must not exist, so a serial number is added to it as necessary.
+ * @return An standard keystore filename.
+ * */
+ private String generateKeyStoreFilename()
+ {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss_SSS"); //$NON-NLS-1$
+ String timestamp = dateFormat.format(Calendar.getInstance().getTime());
+
+ //initial keystore filename with timestamp
+ String keystoreFilenameStr =
+ System.getProperty("user.home") + System.getProperty("file.separator") //$NON-NLS-1$ //$NON-NLS-2$
+ + CertificateManagerNLS.bind(
+ CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilename,
+ timestamp);
+
+ File keystoreFile = new File(keystoreFilenameStr);
+
+ //while file already exists, generate a new one using a new timestamp
+ while (keystoreFile.exists())
+ {
+ timestamp = dateFormat.format(Calendar.getInstance().getTime());
+ keystoreFilenameStr =
+ System.getProperty("user.home") + System.getProperty("file.separator") //$NON-NLS-1$ //$NON-NLS-2$
+ + CertificateManagerNLS
+ .bind(CertificateManagerNLS.CreateKeystorePage_DefaultKeystoreFilename,
+ timestamp);
+ keystoreFile = new File(keystoreFilenameStr);
+ }
+
+ return keystoreFilenameStr;
+ }
+
+ /**
+ * As this page works independently of other pages, it has its own version of performFinish().
+ * Wizards that use this page must call this method to effectively create the new keystore.
+ * @return {@code true} if the keystore were successfully created, {@code false} otherwise.
+ * */
+ public KeyStoreNode createKeyStore()
+ {
+ boolean successfullyCreated = true;
+ File keystoreFile = null;
+ KeyStoreNode keystoreNode = null;
+
+ try
+ {
+ keystoreFile = new File(keystoreFilenameText.getText().trim());
+ if (validateKeyStoreFile(keystoreFile))
+ {
+ keystoreNode =
+ (KeyStoreNode) KeyStoreManager.createKeyStore(keystoreFile,
+ keystoreTypeComboViewer.getCombo().getText(), keystorePasswordText
+ .getText().toCharArray());
+
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keystoreNode);
+ }
+ else
+ {
+ //file already exist and will not be overwritten
+ successfullyCreated = false;
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //in case of error, the keystore wasn't properly created and the file should not be left on file system
+ if (keystoreFile != null)
+ {
+ keystoreFile.delete();
+ }
+
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.CreateKeystorePage_ErrorCreatingKeystore, NLS.bind(
+ CertificateManagerNLS.CreateKeystorePage_ErrorOnKeyStoreFileCreation,
+ keystoreFilenameText.getText()));
+ successfullyCreated = false;
+ }
+
+ if (successfullyCreated && savePassword.getSelection())
+ {
+ savePassword(keystoreFile);
+ }
+
+ return successfullyCreated ? keystoreNode : null;
+ }
+
+ /**
+ * @param keystoreFile
+ */
+ private void savePassword(File keystoreFile)
+ {
+ try
+ {
+ PasswordProvider passwordProvider = new PasswordProvider(keystoreFile);
+ passwordProvider.saveKeyStorePassword(keystorePasswordText.getText());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ EclipseUtils.showWarningDialog(
+ CertificateManagerNLS.CreateKeystorePage_CouldNotSavePassword,
+ e.getLocalizedMessage());
+ }
+ }
+
+ /* If file exists and the user chooses to overwrite it, the key store file is valid and return value is true.
+ * If file exists and the user do not want to overwrite the file, then the keystore file is considered invalid and the return value is false.
+ * If file does not exist, then the file is valid and the return value is true.
+ * */
+ private boolean validateKeyStoreFile(File keystoreFile)
+ {
+ boolean result = true;
+
+ if (keystoreFile.exists())
+ {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+
+ result =
+ MessageDialog.openQuestion(shell,
+ CertificateManagerNLS.CreateKeystorePage_ConfirmFileOverwrite,
+ NLS.bind(CertificateManagerNLS.CreateKeystorePage_ConfirmReplaceFile,
+ keystoreFile.getAbsolutePath()));
+ if (result)
+ {
+ //file will be recreated
+ keystoreFile.delete();
+ }
+ }
+ return result;
+ }
+
+ public String getPassword()
+ {
+ return keystorePassword;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java new file mode 100644 index 0000000..12c0e48 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/CreateKeystoreWizard.java @@ -0,0 +1,122 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+/**
+ *
+ */
+public class CreateKeystoreWizard extends Wizard
+{
+
+ private final CreateKeystorePage createKeystorePage;
+
+ private final CreateKeyWizardPage createKeyPairPage;
+
+ private static final String WIZARD_BANNER = "icons/wizban/create_keystore_wiz.png"; //$NON-NLS-1$
+
+ private static final String KEYSTORE_KEY_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".keystore-key-help-id";
+
+ private KeyStoreNode createdKeystoreNode;
+
+ /**
+ *
+ */
+ public CreateKeystoreWizard()
+ {
+ this(null);
+ }
+
+ public CreateKeystoreWizard(IJobChangeListener createKeystoreJobListener)
+ {
+ setWindowTitle(CertificateManagerNLS.CreateKeystoreWizard_CreateNewKeyStore);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+
+ this.createKeyPairPage = new CreateKeyWizardPage(null, "", createKeystoreJobListener);
+ this.createKeystorePage =
+ new CreateKeystorePage(CertificateManagerNLS.CreateKeystoreWizard_CreateNewKeyStore);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has a generic help that talks about keystore and keys
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getShell(), KEYSTORE_KEY_HELP_ID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish()
+ {
+ createdKeystoreNode = createKeystorePage.createKeyStore();
+ if (createdKeystoreNode != null)
+ {
+ createKeyPairPage.setKeyStore(createdKeystoreNode);
+ createKeyPairPage.setKeyStorePass(createKeystorePage.getPassword());
+ createKeyPairPage.createKey();
+ }
+
+ //check if the keystore was created
+ return (createdKeystoreNode != null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ this.addPage(createKeystorePage);
+ this.addPage(createKeyPairPage);
+ }
+
+ /**
+ * @return the createdKeystoreNode
+ */
+ public KeyStoreNode getCreatedKeystoreNode()
+ {
+ return createdKeystoreNode;
+ }
+
+ public String getCreatedKeystorePassword()
+ {
+ String result = null;
+ if (createKeystorePage != null)
+ {
+ result = createKeystorePage.getPassword();
+ }
+
+ return result;
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java new file mode 100644 index 0000000..b9b0582 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystorePage.java @@ -0,0 +1,417 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import java.io.File;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.common.utilities.FileUtil;
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
+import com.motorolamobility.studio.android.certmanager.core.PasswordProvider;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager;
+
+public class ImportKeystorePage extends WizardPage
+{
+
+ private Text keystoreFilename;
+
+ private ComboViewer keystoreType;
+
+ public static final String IMPORT_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".import_keystore"; //$NON-NLS-1$
+
+ private SelectionListener selectionListener = new SelectionAdapter()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ validatePage();
+ }
+ };
+
+ private boolean userChangedFilename = false;
+
+ private Composite mainComposite;
+
+ private File keystoreFile;
+
+ private String keystoreTypeString;
+
+ protected boolean keystoreAlreadyMapped = false;
+
+ private IKeyStore keyStoreNode;
+
+ /**
+ * @param pageName
+ */
+ protected ImportKeystorePage(String pageName)
+ {
+ super(pageName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent)
+ {
+ mainComposite = new Composite(parent, SWT.FILL);
+ mainComposite.setLayout(new GridLayout(3, false));
+ mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ setTitle(CertificateManagerNLS.ImportKeystorePage_Title);
+ setMessage(CertificateManagerNLS.ImportKeystorePage_Description);
+
+ createFilenameSection(mainComposite);
+ createKeystoreTypeSection(mainComposite);
+
+ validatePage();
+
+ setControl(mainComposite);
+
+ //set help id for this page
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IMPORT_KEYSTORE_HELP_ID);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(mainComposite, IMPORT_KEYSTORE_HELP_ID);
+ }
+
+ private void createFilenameSection(Composite mainComposite)
+ {
+ Label keystoreFilenameLabel = new Label(mainComposite, SWT.NONE);
+ keystoreFilenameLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreFilenameLabel
+ .setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameLabel);
+
+ keystoreFilename = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
+ keystoreFilename.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+ keystoreFilename.addSelectionListener(selectionListener);
+ keystoreFilename.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ userChangedFilename = true;
+ validatePage();
+ }
+ });
+
+ Button chooseLocation = new Button(mainComposite, SWT.PUSH);
+ chooseLocation.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
+ chooseLocation.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreFilenameBrowse);
+ chooseLocation.addSelectionListener(new SelectionAdapter()
+ {
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ Shell shell = Display.getCurrent().getActiveShell();
+
+ FileDialog dialog = new FileDialog(shell, SWT.OPEN);
+
+ String keystoreFilenameStr = dialog.open();
+
+ if (keystoreFilenameStr != null)
+ {
+ keystoreFilename.setText(keystoreFilenameStr);
+ keystoreType.getCombo().setFocus();
+ }
+ }
+ });
+ }
+
+ private void createKeystoreTypeSection(Composite parent)
+ {
+ Label keystoreTypeLabel = new Label(parent, SWT.NONE);
+ keystoreTypeLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ keystoreTypeLabel.setText(CertificateManagerNLS.CreateKeystorePage_KeystoreType);
+
+ keystoreType = new ComboViewer(parent, SWT.READ_ONLY);
+ keystoreType.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false, 1, 1));
+ keystoreType.setContentProvider(new IStructuredContentProvider()
+ {
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
+ {
+ //do nothing
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object[] getElements(Object inputElement)
+ {
+ return ((List<String>) inputElement).toArray();
+ }
+ });
+ keystoreType.setLabelProvider(new ILabelProvider()
+ {
+
+ @Override
+ public void removeListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property)
+ {
+ return false;
+ }
+
+ @Override
+ public void dispose()
+ {
+ //do nothing
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener)
+ {
+ //do nothing
+ }
+
+ @Override
+ public String getText(Object element)
+ {
+ return (String) element;
+ }
+
+ @Override
+ public Image getImage(Object element)
+ {
+ return null;
+ }
+ });
+
+ keystoreType.setInput(KeyStoreManager.getInstance().getAvailableTypes());
+
+ for (int i = 0; i < keystoreType.getCombo().getItemCount(); i++)
+ {
+ if (keystoreType.getCombo().getItem(i)
+ .compareToIgnoreCase(KeyStoreManager.getInstance().getDefaultType()) == 0)
+ {
+ keystoreType.getCombo().select(i);
+ }
+ }
+
+ keystoreType.getCombo().addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ validatePage();
+ }
+ });
+
+ //fill the third column with a blank label
+ Label separator2 = new Label(parent, SWT.NONE);
+ separator2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1));
+ }
+
+ protected boolean validatePage()
+ {
+ String errorMessage = null;
+ boolean pageComplete = true;
+ keystoreAlreadyMapped = false;
+
+ keystoreFile = new File(keystoreFilename.getText());
+ keystoreTypeString = keystoreType.getCombo().getText();
+
+ if (keystoreType.getCombo().getText().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.ImportKeystorePage_KeystoreTypeCannotBeEmpty;
+ pageComplete = false;
+ }
+
+ if (userChangedFilename && !keystoreFile.exists())
+ {
+ errorMessage =
+ NLS.bind(CertificateManagerNLS.ImportKeystorePage_FileDoesNotExist,
+ keystoreFilename.getText());
+ pageComplete = false;
+ }
+
+ if (keystoreFile.exists())
+ {
+ if (keystoreFile.isFile())
+ {
+ int fileSize = -1;
+ try
+ {
+ fileSize = FileUtil.getFileSize(keystoreFile);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ if (fileSize <= 0)
+ {
+ errorMessage =
+ NLS.bind(CertificateManagerNLS.ImportKeystorePage_FileEmpty,
+ keystoreFilename.getText());
+ pageComplete = false;
+ }
+ }
+ else if (keystoreFile.isDirectory())
+ {
+ errorMessage =
+ NLS.bind(
+ CertificateManagerNLS.ImportKeystorePage_DirectoryNotAllowedErrorMsg,
+ keystoreFilename.getText());
+ pageComplete = false;
+ }
+ }
+
+ if (keystoreFilename.getText().isEmpty())
+ {
+ errorMessage = CertificateManagerNLS.ImportKeystorePage_FilenameCannotBeEmpty;
+ pageComplete = false;
+ }
+
+ if (KeyStoreManager.getInstance().isKeystoreMapped(keystoreFile))
+ {
+ errorMessage =
+ NLS.bind(CertificateManagerNLS.ImportKeystorePage_KeystoreAlreadyMapped,
+ keystoreFilename.getText());
+ keystoreAlreadyMapped = true;
+ pageComplete = false;
+ }
+
+ setErrorMessage(errorMessage);
+ setPageComplete(pageComplete);
+
+ return pageComplete;
+ }
+
+ /**
+ * Import the keystore using the information provided by the user.
+ * @return True if the keystore was imported, false otherwise.
+ * */
+ protected boolean importKeystore(String password, boolean savePassword)
+ {
+ boolean successfullyImported = true;
+
+ validatePage();
+
+ if (isPageComplete())
+ {
+
+ KeyStoreNode keyStoreNode =
+ new KeyStoreNode(keystoreFile, keystoreType.getCombo().getText());
+
+ try
+ {
+ SigningAndKeysModelManager.getInstance().mapKeyStore(keyStoreNode);
+
+ if (savePassword)
+ {
+ PasswordProvider passwordProvider = new PasswordProvider(keystoreFile);
+ passwordProvider.saveKeyStorePassword(password);
+ }
+ }
+ catch (KeyStoreManagerException e)
+ {
+ //keystore already mapped
+ EclipseUtils.showErrorDialog(
+ CertificateManagerNLS.ImportKeystorePage_CouldNotImportKeystore,
+ e.getMessage());
+ successfullyImported = false;
+ }
+ }
+ else
+ {
+ successfullyImported = false;
+ }
+
+ return successfullyImported;
+ }
+
+ /**
+ * Import the keystore using the information provided by the user.
+ * @return True if the keystore was imported, false otherwise.
+ * */
+ public boolean importKeystore()
+ {
+ return importKeystore(null, false);
+ }
+
+ /**
+ *
+ * @return
+ */
+ protected IKeyStore getSelectedKeystore()
+ {
+ if ((keyStoreNode == null)
+ || !keyStoreNode.getFile().equals(keystoreFile)
+ || ((keyStoreNode.getFile().equals(keystoreFile)) && keyStoreNode.getType()
+ .equalsIgnoreCase(keystoreTypeString)))
+ {
+ keyStoreNode = new KeyStoreNode(keystoreFile, keystoreTypeString);
+ }
+ return keyStoreNode;
+ }
+
+ /**
+ * @return the mainComposite
+ */
+ protected Composite getMainComposite()
+ {
+ return mainComposite;
+ }
+
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java new file mode 100644 index 0000000..55e6d97 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/ImportKeystoreWizard.java @@ -0,0 +1,72 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+public class ImportKeystoreWizard extends Wizard
+{
+ ImportKeystorePage importKeystorePage = null;
+
+ private static final String WIZARD_BANNER = "icons/wizban/import_keystore_wiz.png"; //$NON-NLS-1$
+
+ public ImportKeystoreWizard()
+ {
+ setWindowTitle(CertificateManagerNLS.ImportKeystorePage_Title);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has the same help as its page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getShell(), ImportKeystorePage.IMPORT_KEYSTORE_HELP_ID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish()
+ {
+ return importKeystorePage.importKeystore();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ importKeystorePage =
+ new ImportKeystorePage(CertificateManagerNLS.ImportKeystoreWizard_ImportKeystore);
+ addPage(importKeystorePage);
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java new file mode 100644 index 0000000..cca8989 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignaturePage.java @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.ui.wizards; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.internal.resources.Folder; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; +import org.eclipse.ui.dialogs.ISelectionStatusValidator; +import org.eclipse.ui.model.WorkbenchContentProvider; +import org.eclipse.ui.model.WorkbenchLabelProvider; +import org.eclipse.ui.views.navigator.ResourceComparator; + +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; + +@SuppressWarnings("restriction") +public class RemoveExternalPackageSignaturePage extends WizardPage +{ + private Text sourceDirText = null; + + private Button browseDirButton = null; + + private Button workspaceDirButton = null; + + private Tree packagesTree = null; + + private Button selectAllButton = null; + + private Button deselectAllButton = null; + + private WizardSelection selection = null; + + protected Composite mainComposite = null; + + /** + * Create a new wizard page based on selection + * + * @param pageName + * the page name + * @param selection + * the selection + */ + public RemoveExternalPackageSignaturePage(String pageName, IStructuredSelection selection) + { + super(pageName); + setDescription(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION); + setTitle(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE); + this.selection = new WizardSelection(selection); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets + * .Composite) + */ + @Override + public void createControl(Composite parent) + { + this.mainComposite = new Composite(parent, SWT.NULL); + // create new layout with 3 columns of different sizes + GridLayout layout = new GridLayout(4, false); + this.mainComposite.setLayout(layout); + + Label sourceDirLabel = new Label(this.mainComposite, SWT.NONE); + sourceDirLabel.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL); + + GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + sourceDirLabel.setLayoutData(layoutData); + + this.sourceDirText = new Text(this.mainComposite, SWT.BORDER); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); + this.sourceDirText.setLayoutData(layoutData); + this.sourceDirText.addListener(SWT.Modify, new SourceDirectoryTextListener()); + + this.browseDirButton = new Button(this.mainComposite, SWT.PUSH); + this.browseDirButton.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + this.browseDirButton.setLayoutData(layoutData); + this.browseDirButton.addListener(SWT.Selection, new BrowseButtonListener()); + + this.workspaceDirButton = new Button(this.mainComposite, SWT.PUSH); + this.workspaceDirButton.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + this.workspaceDirButton.setLayoutData(layoutData); + this.workspaceDirButton.addListener(SWT.Selection, new WorkspaceButtonListener()); + + createExtendedArea(this.mainComposite); + + createPackageTreeLabel(); + + this.packagesTree = new Tree(this.mainComposite, SWT.BORDER | SWT.CHECK | SWT.V_SCROLL); + layoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 2); + layoutData.heightHint = 150; + this.packagesTree.setLayoutData(layoutData); + this.packagesTree.addListener(SWT.Selection, new TreeSelectionListener()); + + Composite selectionButtons = new Composite(this.mainComposite, SWT.FILL); + layoutData = new GridData(SWT.FILL, SWT.TOP, false, true, 1, 2); + selectionButtons.setLayoutData(layoutData); + FillLayout row = new FillLayout(SWT.VERTICAL); + row.spacing = 3; + selectionButtons.setLayout(row); + + this.selectAllButton = new Button(selectionButtons, SWT.PUSH); + this.selectAllButton + .setText(CertificateManagerNLS.PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON); + SelectionButtonsListener selectionButtonsListener = new SelectionButtonsListener(); + this.selectAllButton.addListener(SWT.Selection, selectionButtonsListener); + + this.deselectAllButton = new Button(selectionButtons, SWT.PUSH); + this.deselectAllButton + .setText(CertificateManagerNLS.PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON); + this.deselectAllButton.addListener(SWT.Selection, selectionButtonsListener); + + this.sourceDirText.setText(this.selection.getSelectedDirectory()); + populateTree(this.selection.getSelectedPackages()); + updatePageComplete(); + setControl(this.mainComposite); + } + + protected void createPackageTreeLabel() + { + GridData layoutData; + Label packagesLabel = new Label(this.mainComposite, SWT.NONE); + packagesLabel + .setText(CertificateManagerNLS.RemoveExternalPackageSignaturePage_Package_Tree_Label); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1); + packagesLabel.setLayoutData(layoutData); + } + + /** + * Create a composite area after the basic composite Subclasses that need + * more than the basic package selection screen should override this method + * + * @param mainComposite + */ + protected void createExtendedArea(Composite parent) + { + PlatformUI + .getWorkbench() + .getHelpSystem() + .setHelp(parent, + CertificateManagerActivator.UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID); + } + + /** + * Populates the tree with the packages of base dir Requires a valid folder + * set as source dir + */ + private void populateTree(List<String> selection) + { + File sourceDir = getSourcePath().toFile(); + Color gray = new Color(null, 130, 130, 130); + this.packagesTree.removeAll(); + if (sourceDir.isDirectory() && sourceDir.canWrite()) + { + File[] list = sourceDir.listFiles(); + for (File file : list) + { + if (file.canRead() && file.isFile() && file.getName().endsWith("apk")) //$NON-NLS-1$ + { + TreeItem fileItem = new TreeItem(this.packagesTree, SWT.NONE); + String text = file.getName(); + if (!file.canWrite()) + { + text += " [" + CertificateManagerNLS.READ_ONLY_TEXT //$NON-NLS-1$ + + "]"; //$NON-NLS-1$ + fileItem.setForeground(gray); + } + + fileItem.setText(text); + fileItem.setData(file); + if ((selection != null) && selection.contains(file.getName()) + && file.canWrite()) + { + fileItem.setChecked(true); + } + } + } + } + } + + /** + * Validates if the source directory is valid one + * + * @return true if the source dir text is valid, false otherwise + */ + private boolean isSourceDirValid() + { + + String messageAux = null; + int severity = IMessageProvider.NONE; + + /* + * Check if the selected location is valid, even if non existent. + */ + IPath path = new Path(this.sourceDirText.getText()); + + // Test if path is blank, to warn user instead of show an error message + if (this.sourceDirText.getText().equals("")) //$NON-NLS-1$ + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY; + severity = IMessageProvider.INFORMATION; + } + + /* + * Do Win32 Validation + */ + if ((messageAux == null) && Platform.getOS().equalsIgnoreCase(Platform.OS_WIN32)) + { + // test path size + if (path.toString().length() > 255) + { + messageAux = + + CertificateManagerNLS.SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG; + severity = IMessageProvider.WARNING; + } + String device = path.getDevice(); + File deviceFile = null; + if (device != null) + { + deviceFile = new File(path.getDevice()); + } + + if ((device != null) && !deviceFile.exists()) + { + messageAux = + + CertificateManagerNLS.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE + " [" + + device + "]"; + severity = IMessageProvider.ERROR; + } + + } + // test if path is absolute + if (messageAux == null) + { + if (!path.isAbsolute() || !path.toFile().exists()) + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID; + severity = IMessageProvider.ERROR; + } + } + + if (messageAux == null) + { + for (String folderName : path.segments()) + { + if (!ResourcesPlugin.getWorkspace().validateName(folderName, IResource.FOLDER) + .isOK()) + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID; + severity = IMessageProvider.ERROR; + + } + } + } + + if ((messageAux == null) && ((path.toFile().exists() && !path.toFile().isDirectory()))) + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY; + severity = IMessageProvider.ERROR; + + } + + /* + * Setting message + */ + if (messageAux == null) + { + messageAux = CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION; + severity = IMessageProvider.NONE; + } + setMessage(messageAux, severity); + return severity == IMessageProvider.NONE; + } + + /** + * @return the path of base dir where packages are located + */ + public IPath getSourcePath() + { + return new Path(this.sourceDirText.getText()); + } + + /** + * + * @return the list with selected packages + */ + public List<String> getSelectedPackages() + { + ArrayList<String> selected = new ArrayList<String>(); + for (TreeItem item : this.packagesTree.getItems()) + { + if (item.getChecked()) + { + selected.add(item.getData().toString()); + } + } + + return selected; + } + + /** + * Update the page status, validating each field of this page Subclasses + * that overrides createExtendedArea method should override this method too + * to validate the new fields + */ + public void updatePageComplete() + { + + String messageAux = null; + int severity = IMessageProvider.NONE; + + /* + * Check if there are available certificates and if selection isn't null + */ + if (isSourceDirValid()) + { + if (this.packagesTree.getItemCount() == 0) + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES; + severity = IMessageProvider.ERROR; + } + } + else + { + messageAux = getMessage(); + severity = getMessageType(); + } + + if ((messageAux == null) && (getSelectedPackages().size() == 0)) + { + messageAux = + + CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED; + severity = IMessageProvider.INFORMATION; + } + + if (messageAux == null) + { + messageAux = + + CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION; + severity = IMessageProvider.NONE; + } + + setMessage(messageAux, severity); + setPageComplete(severity == IMessageProvider.NONE); + + } + + /** + * This class implements the listener of filesystem button, opening the browse + * window and updating the dir text + */ + class BrowseButtonListener implements Listener + { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets + * .Event) + */ + @Override + public void handleEvent(Event event) + { + DirectoryDialog dialog = + new DirectoryDialog( + RemoveExternalPackageSignaturePage.this.mainComposite.getShell()); + dialog.setFilterPath(!RemoveExternalPackageSignaturePage.this.sourceDirText.getText() + .trim().equals("") ? RemoveExternalPackageSignaturePage.this.sourceDirText + .getText() : null); + String path = dialog.open(); + if (path != null) + { + RemoveExternalPackageSignaturePage.this.sourceDirText.setText(path); + populateTree(null); + updatePageComplete(); + } + } + + } + + /** + * This class implements the listener of workspace button, opening the browse + * window and updating the dir text + */ + class WorkspaceButtonListener implements Listener + { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets + * .Event) + */ + @Override + public void handleEvent(Event event) + { + ElementTreeSelectionDialog dialog = + new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(), + new WorkbenchContentProvider()); + dialog.setTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE); + dialog.setMessage(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_CHOOSE); + + // set the workspace as the limit + dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); + dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); + + //don't display files + dialog.addFilter(new ViewerFilter() + { + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) + { + boolean filtered = false; + + if (element instanceof IFile) + { + filtered = true; + } + return !filtered; + } + }); + + //user can select only one folder + dialog.setValidator(new ISelectionStatusValidator() + { + + @Override + public IStatus validate(Object[] selection) + { + IStatus valid = + new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, ""); //$NON-NLS-1$ + if (selection.length == 1) + { + if (selection[0] instanceof Folder) + { + valid = + new Status(IStatus.OK, CertificateManagerActivator.PLUGIN_ID, + ""); //$NON-NLS-1$ + } + } + return valid; + } + }); + + String path = null; + if (dialog.open() == IDialogConstants.OK_ID) + { + Folder resource = (Folder) dialog.getFirstResult(); + path = resource.getLocation().toString(); + } + + if (path != null) + { + RemoveExternalPackageSignaturePage.this.sourceDirText.setText(path); + populateTree(null); + updatePageComplete(); + } + } + } + + /** + * Listener to validate any SourceDirectory text Change + */ + class SourceDirectoryTextListener implements Listener + { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets + * .Event) + */ + @Override + public void handleEvent(Event event) + { + RemoveExternalPackageSignaturePage.this.packagesTree.removeAll(); + if (isSourceDirValid()) + { + populateTree(null); + } + updatePageComplete(); + } + + } + + /** + * This class handles clicks on select all and deselect all buttons + */ + class SelectionButtonsListener implements Listener + { + + /** + * Check/Uncheck all items + * + * @param check + * : true for check, false for unckeck + */ + private void setCheckedAll(boolean check) + { + for (TreeItem item : RemoveExternalPackageSignaturePage.this.packagesTree.getItems()) + { + item.setChecked(check); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets + * .Event) + */ + @Override + public void handleEvent(Event event) + { + if (event.widget == RemoveExternalPackageSignaturePage.this.selectAllButton) + { + setCheckedAll(true); + } + else if (event.widget == RemoveExternalPackageSignaturePage.this.deselectAllButton) + { + setCheckedAll(false); + } + updatePageComplete(); + } + + } + + /** + * Listener to update wizard status according tree selection + */ + class TreeSelectionListener implements Listener + { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets + * .Event) + */ + @Override + public void handleEvent(Event event) + { + updatePageComplete(); + } + + } + + /** + * This class gets the workspace selection and makes a suitable selection to + * the wizard + */ + class WizardSelection + { + private ArrayList<String> packages = null; + + private IPath directory = null; + + public WizardSelection(IStructuredSelection selection) + { + this.packages = new ArrayList<String>(); + Iterator<?> iterator = selection.iterator(); + while (iterator.hasNext()) + { + Object obj = iterator.next(); + if (obj instanceof IFile) + { + IFile file = (IFile) obj; + + if (file.getLocation().getFileExtension().equals("apk")) //$NON-NLS-1$ + { + if (this.directory == null) + { + this.directory = file.getLocation().removeLastSegments(1); + this.packages.add(file.getName()); + } + else + { + if (file.getLocation().matchingFirstSegments(this.directory) == this.directory + .segmentCount()) + { + this.packages.add(file.getName()); + } + } + } + } + else if (obj instanceof IFolder) + { + if (this.directory == null) + { + this.directory = ((IFolder) obj).getLocation(); + } + } + } + if (this.directory == null) + { + this.directory = new Path(""); //$NON-NLS-1$ + } + } + + /** + * + * @return the selected directory + */ + public String getSelectedDirectory() + { + return this.directory.toOSString(); + } + + /** + * + * @return the selected packages + */ + public List<String> getSelectedPackages() + { + return this.packages; + } + + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java new file mode 100644 index 0000000..7783262 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/RemoveExternalPackageSignatureWizard.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.ui.wizards; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarFile; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; +import com.motorolamobility.studio.android.certmanager.packaging.PackageFile; + +/** + * This Wizard removes a signature of a package. based on a root dir, It shows a + * list of packages to remove signature + */ +public class RemoveExternalPackageSignatureWizard extends Wizard +{ + private RemoveExternalPackageSignaturePage page = null; + + public RemoveExternalPackageSignatureWizard(IStructuredSelection selection) + { + setWindowTitle(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE); + setNeedsProgressMonitor(true); + this.page = new RemoveExternalPackageSignaturePage("removeSigPage", selection); + setDefaultPageImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin( + CertificateManagerActivator.PLUGIN_ID, + CertificateManagerActivator.REMOVE_SIGNATURE_WIZ_BAN)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.wizard.Wizard#addPages() + */ + @Override + public void addPages() + { + addPage(this.page); + } + + /** + * Finishes this wizard removing packages signatures + */ + @Override + public boolean performFinish() + { + final List<String> defectivePackages = new ArrayList<String>(); + IRunnableWithProgress finishAction = new IRunnableWithProgress() + { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException + { + List<String> selectedFiles = + RemoveExternalPackageSignatureWizard.this.page.getSelectedPackages(); + monitor.beginTask(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE, + selectedFiles.size()); + for (String selected : selectedFiles) + { + File file = new File(selected); + monitor.setTaskName(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_OPERATION + + " " + file.getName()); + if ((file != null) && file.exists() && file.isFile() && file.canWrite()) + { + OutputStream fileToWrite = null; + JarFile jar = null; + PackageFile pack = null; + try + { + // Open package and remove signature + jar = new JarFile(file); + pack = new PackageFile(jar); + try + { + pack.removeMetaEntryFiles(); + } + catch (IOException e) + { + StudioLogger.error( + RemoveExternalPackageSignatureWizard.class.toString(), + "Impossible to delete temporary files"); + throw e; + } + + // Write the new package file + fileToWrite = new FileOutputStream(file); + pack.write(fileToWrite); + PackageFile.zipAlign(file); + } + catch (IOException e) + { + defectivePackages.add(selected); + StudioLogger.error( + RemoveExternalPackageSignatureWizard.class.toString(), + "Impossible write to package: " + selected + " " + + e.getMessage()); + } + catch (SecurityException e) + { + defectivePackages.add(selected); + StudioLogger.error( + RemoveExternalPackageSignatureWizard.class.toString(), + "Impossible write to package: " + selected + " " + + e.getMessage()); + } + finally + { + + System.gc(); // Force garbage collector to avoid + // errors when deleting temp files + + try + { + if (jar != null) + { + jar.close(); + } + + if (pack != null) + { + pack.removeTemporaryEntryFiles(); + } + + if (fileToWrite != null) + { + fileToWrite.close(); + } + } + catch (IOException e) + { + // Silent exception. Only log the deletion + // exception. + StudioLogger.error(CertificateManagerActivator.PLUGIN_ID, + "Deleting temporary files"); + } + } + } + else + { + defectivePackages.add(selected); + } + monitor.worked(1); + } + monitor.done(); + } + + }; + + try + { + PlatformUI.getWorkbench().getProgressService() + .runInUI(new ProgressMonitorDialog(getShell()), finishAction, null); + } + catch (InvocationTargetException e1) + { + StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(), + "Error running finish actions"); + } + catch (InterruptedException e1) + { + StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(), + "Error running finish actions"); + } + + if (ResourcesPlugin.getWorkspace().getRoot().getLocation() + .isPrefixOf(this.page.getSourcePath())) + { + org.eclipse.ui.actions.WorkspaceModifyOperation op = + new org.eclipse.ui.actions.WorkspaceModifyOperation() + { + + @Override + protected void execute(IProgressMonitor monitor) throws CoreException, + InvocationTargetException, InterruptedException + { + for (IContainer container : ResourcesPlugin + .getWorkspace() + .getRoot() + .findContainersForLocation( + RemoveExternalPackageSignatureWizard.this.page + .getSourcePath())) + { + + container.refreshLocal(IResource.DEPTH_INFINITE, monitor); + } + + } + + }; + try + { + PlatformUI.getWorkbench().getProgressService().run(false, false, op); + } + catch (InvocationTargetException e) + { + StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(), + "Error refreshing workspace"); + } + catch (InterruptedException e) + { + StudioLogger.error(RemoveExternalPackageSignatureWizard.class.toString(), + "Error refreshing workspace"); + } + } + + if (!defectivePackages.isEmpty()) + { + MultiStatus errors = + new MultiStatus(CertificateManagerActivator.PLUGIN_ID, IStatus.ERROR, + CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON, null); + for (String defect : defectivePackages) + { + errors.add(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, defect)); + } + + ErrorDialog errorBox = + new ErrorDialog(getShell(), + CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE, + CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_ERROR, errors, + IStatus.ERROR); + errorBox.open(); + } + + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets + * .Composite) + */ + @Override + public void createPageControls(Composite pageContainer) + { + super.createPageControls(pageContainer); + PlatformUI + .getWorkbench() + .getHelpSystem() + .setHelp(getShell(), + CertificateManagerActivator.UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java new file mode 100644 index 0000000..71ecaef --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystorePage.java @@ -0,0 +1,200 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+
+/**
+ * Enables selection of a keystore (similar to {@link ImportKeystorePage} functionality.
+ * It adds a checkbox button that enables user to add the imported keystore into Signing and Keys view.
+ */
+public class SelectExistentKeystorePage extends ImportKeystorePage
+{
+ private static final int SMALL_TEXT_SIZE = 64;
+
+ public static final String SELECT_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".select_keystore"; //$NON-NLS-1$
+
+ private Button alsoImportIntoView = null;
+
+ private boolean importIntoView = true;
+
+ private Label keystorePasswordLabel;
+
+ private Text keystorePassword;
+
+ private Button savePasswordCheckBox;
+
+ private boolean canSavePassword = false;
+
+ private String password = null;
+
+ private SelectionListener selectionListener = new SelectionAdapter()
+ {
+
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ validatePage();
+ }
+ };
+
+ protected SelectExistentKeystorePage(String pageName)
+ {
+ super(pageName);
+ }
+
+ @Override
+ public void createControl(Composite parent)
+ {
+ super.createControl(parent);
+ setTitle(CertificateManagerNLS.SelectExistentKeystorePage_WizardPageTitle);
+ setMessage(CertificateManagerNLS.SelectExistentKeystorePage_WizardPageMessage);
+
+ //KEYSTORE PASSWORD SECTION
+ keystorePasswordLabel = new Label(getMainComposite(), SWT.NONE);
+ keystorePasswordLabel
+ .setText(CertificateManagerNLS.SelectExistentKeystorePage_KeystorePasswordLabel); //$NON-NLS-2$
+
+ keystorePassword = new Text(getMainComposite(), SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
+ keystorePassword.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ keystorePassword.setTextLimit(SMALL_TEXT_SIZE);
+ keystorePassword.addSelectionListener(selectionListener);
+ keystorePassword.addModifyListener(new ModifyListener()
+ {
+
+ @Override
+ public void modifyText(ModifyEvent e)
+ {
+ password = keystorePassword.getText();
+ validatePage();
+ }
+ });
+
+ //Creates the save password checkbox
+ savePasswordCheckBox = new Button(getMainComposite(), SWT.CHECK);
+ savePasswordCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ savePasswordCheckBox.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword);
+ savePasswordCheckBox.setSelection(false);
+ savePasswordCheckBox.setVisible(importIntoView);
+ savePasswordCheckBox.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ //update according to check status
+ canSavePassword = savePasswordCheckBox.getSelection();
+ }
+
+ });
+
+ alsoImportIntoView = new Button(getMainComposite(), SWT.CHECK);
+ alsoImportIntoView.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
+ alsoImportIntoView
+ .setText(CertificateManagerNLS.SelectExistentKeystorePage_CheckboxText_AlsoImportIntoSigningView);
+ alsoImportIntoView.setSelection(importIntoView);
+ alsoImportIntoView.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ //update according to check status
+ importIntoView = alsoImportIntoView.getSelection();
+ savePasswordCheckBox.setEnabled(importIntoView);
+ canSavePassword = importIntoView && savePasswordCheckBox.getSelection();
+ }
+
+ });
+
+ //set help id for this page
+ PlatformUI.getWorkbench().getHelpSystem()
+ .setHelp(getMainComposite(), SELECT_KEYSTORE_HELP_ID);
+ }
+
+ /**
+ * @return the importIntoView
+ */
+ public boolean needToImportIntoView()
+ {
+ return importIntoView;
+ }
+
+ /**
+ * @return the password
+ */
+ protected String getPassword()
+ {
+ return password;
+ }
+
+ @Override
+ protected boolean validatePage()
+ {
+ boolean pageComplete = super.validatePage();
+
+ String infoMessage = CertificateManagerNLS.SelectExistentKeystorePage_WizardPageMessage;
+ String errorMessage = null;
+
+ if (pageComplete)
+ {
+ if (!keystoreAlreadyMapped)
+ {
+ if (keystorePassword.getText().isEmpty())
+ {
+ pageComplete = false;
+ errorMessage = CertificateManagerNLS.CertificateBlock_EnterPassword_InfoMessage;
+ }
+ setMessage(infoMessage);
+ setErrorMessage(errorMessage);
+ setPageComplete(pageComplete);
+ }
+ }
+
+ return pageComplete;
+ }
+
+ /**
+ * @return the canSavePassword
+ */
+ protected boolean canSavePassword()
+ {
+ return canSavePassword;
+ }
+
+ /* (non-Javadoc)
+ * @see com.motorolamobility.studio.android.certmanager.ui.wizards.ImportKeystorePage#importKeystore()
+ */
+ @Override
+ public boolean importKeystore()
+ {
+ return importKeystore(getPassword(), canSavePassword());
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java new file mode 100644 index 0000000..d5612df --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SelectExistentKeystoreWizard.java @@ -0,0 +1,141 @@ +/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 com.motorolamobility.studio.android.certmanager.ui.wizards;
+
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+
+import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
+import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
+import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
+import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
+import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
+import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode;
+
+/**
+ * Enables selection of a keystore (similar to {@link ImportKeystoreWizard} functionality.
+ * It adds a checkbox button that enables user to add the imported keystore into Signing and Keys view.
+ */
+public class SelectExistentKeystoreWizard extends Wizard
+{
+ protected SelectExistentKeystorePage selectExistentKeystorePage = null;
+
+ private static final String WIZARD_BANNER = "icons/wizban/import_keystore_wiz.png"; //$NON-NLS-1$
+
+ public static final String SELECT_KEYSTORE_HELP_ID = CertificateManagerActivator.PLUGIN_ID
+ + ".select_keystore"; //$NON-NLS-1$
+
+ public SelectExistentKeystoreWizard()
+ {
+ setWindowTitle(CertificateManagerNLS.ImportKeystoreWizard_ImportKeystore);
+ setDefaultPageImageDescriptor(CertificateManagerActivator.imageDescriptorFromPlugin(
+ CertificateManagerActivator.PLUGIN_ID, WIZARD_BANNER));
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#createPageControls(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPageControls(Composite pageContainer)
+ {
+ super.createPageControls(pageContainer);
+
+ //the shell has the same help as its page
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getShell(), SELECT_KEYSTORE_HELP_ID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#performFinish()
+ */
+ @Override
+ public boolean performFinish()
+ {
+ //check password and keystore type before importing
+ IKeyStore iKeyStore = selectExistentKeystorePage.getSelectedKeystore();
+ if (iKeyStore instanceof KeyStoreNode)
+ {
+ KeyStoreNode keyStoreNode = (KeyStoreNode) iKeyStore;
+ try
+ {
+ keyStoreNode.isPasswordValid(selectExistentKeystorePage.getPassword());
+ }
+ catch (KeyStoreManagerException e)
+ {
+ selectExistentKeystorePage
+ .setErrorMessage(CertificateManagerNLS.SelectExistentKeystoreWizard_Error_KeystoreType);
+ //let dialog opened
+ return false;
+ }
+ catch (InvalidPasswordException e)
+ {
+ selectExistentKeystorePage
+ .setErrorMessage(CertificateManagerNLS.SelectExistentKeystoreWizard_Error_InvalidPassword);
+ //let dialog opened
+ return false;
+ }
+ }
+
+ if (selectExistentKeystorePage.needToImportIntoView())
+ {
+ //if user asked to import item in the Signing and keys view
+ selectExistentKeystorePage.importKeystore();
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.wizard.Wizard#addPages()
+ */
+ @Override
+ public void addPages()
+ {
+ selectExistentKeystorePage =
+ new SelectExistentKeystorePage(
+ CertificateManagerNLS.SelectExistentKeystoreWizard_BrowseExistentKeystore_PageTitle);
+ addPage(selectExistentKeystorePage);
+ }
+
+ /**
+ *
+ * @return
+ */
+ public IKeyStore getSelectedKeystore()
+ {
+ IKeyStore iKeyStore = selectExistentKeystorePage.getSelectedKeystore();
+ return iKeyStore;
+ }
+
+ /**
+ *
+ * @return true if need to import into view, false otherwise
+ */
+ public boolean canSavePassword()
+ {
+ return selectExistentKeystorePage.canSavePassword();
+ }
+
+ /**
+ *
+ * @return true if need to import into view, false otherwise
+ */
+ public String getPassword()
+ {
+ return selectExistentKeystorePage.getPassword();
+ }
+}
diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java new file mode 100644 index 0000000..75898eb --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackagePage.java @@ -0,0 +1,559 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.ui.wizards; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager; +import com.motorolamobility.studio.android.certmanager.core.PasswordProvider; +import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; +import com.motorolamobility.studio.android.certmanager.ui.model.EntryNode; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry; +import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreNode; + +/** + * This class implements the page of signature of external packages wizard It + * extends the page that removes the signature and implements the needed fields + */ +public class SignExternalPackagePage extends RemoveExternalPackageSignaturePage +{ + + private Label keystoreLabel = null; + + private Label keysLabel = null; + + private Combo keystoreCombo = null; + + private Text keystorePassword = null; + + private Button loadKeystore = null; + + private Button savePassword = null; + + private Combo keysCombo = null; + + private String keyEntryPassword; + + private String keyStoreType; + + PasswordProvider pP = null; + + private IKeyStore initialSelectedKeyStore = null; + + private IKeyStoreEntry initialSelectedEntry = null; + + private IKeyStore selectedKeystore = null; + + SelectionAdapter loadKeysSelectionAdapter = new SelectionAdapter() + { + @Override + public void widgetDefaultSelected(SelectionEvent e) + { + widgetSelected(e); + }; + + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) + { + setKeyEntries(); + } + }; + + /** + * Create a new wizard page based on selection + * + * @param pageName + * the page name + * @param selection + * the selection + */ + public SignExternalPackagePage(String pageName, IStructuredSelection selection, + IKeyStore selectedIKeyStore, IKeyStoreEntry selectedEntry) + { + super(pageName, selection); + this.initialSelectedKeyStore = selectedIKeyStore; + this.initialSelectedEntry = selectedEntry; + setDescription(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION); + setTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE); + } + + private HashMap<String, IKeyStore> getAvailableKeystores() + { + HashMap<String, IKeyStore> keystores = new HashMap<String, IKeyStore>(); + Iterator<IKeyStore> iterator = null; + try + { + if ((KeyStoreManager.getInstance() != null) + && (KeyStoreManager.getInstance().getKeyStores() != null)) + { + iterator = KeyStoreManager.getInstance().getKeyStores().iterator(); + } + } + catch (KeyStoreManagerException e) + { + StudioLogger.error(this.getClass(), "Error retrieving keystore list", e); //$NON-NLS-1$ + } + + while ((iterator != null) && (iterator.hasNext())) + { + KeyStoreNode keystore = (KeyStoreNode) iterator.next(); + + keystores.put(keystore.toString(), keystore); + } + return keystores; + + } + + /** + * @param keystorePath + * @return key strings for the selected keystore + */ + private final String[] getAvailableEntriesForKeystore(IKeyStore keystore) + { + ArrayList<String> entries = new ArrayList<String>(); + + if (keystore != null) + { + + pP = new PasswordProvider(keystore.getFile()); + String password = null; + try + { + // retrieve the saved password + password = pP.getKeyStorePassword(false); + } + catch (KeyStoreManagerException e1) + { + StudioLogger.error(this.getClass(), "Error retrieving keys from keystore", e1); //$NON-NLS-1$ + } + + if (password == null) + { + // password is not saved + if (!this.keystorePassword.getText().isEmpty()) + { + // get the password from the wizard + password = this.keystorePassword.getText(); + } + } + else + { + // the password was saved + try + { + keystore.isPasswordValid(password); + } + catch (InvalidPasswordException e) + { + if (!this.keystorePassword.getText().isEmpty()) + { + // the saved password is invalid, get the password from the wizard + password = this.keystorePassword.getText(); + } + } + catch (KeyStoreManagerException e) + { + //this exception should never happen here as it was handled at some point before + StudioLogger.error("This keystore was imported with wrong store type"); //$NON-NLS-1$ + } + } + try + { + try + { + if (password != null) + { + // validate the password that was saved or from the wizard + keystore.isPasswordValid(password); + if (this.keystorePassword.getText().isEmpty()) + { + // block the password fields if the password saved is valid + this.keystorePassword.setText(password); + this.keystorePassword.setEnabled(false); + this.savePassword.setSelection(true); + this.savePassword.setEnabled(false); + this.loadKeystore.setEnabled(false); + } + } + List<IKeyStoreEntry> keys = keystore.getEntries(password); + + if ((keys.size() > 0) && (password != null)) + { + this.keyStoreType = keystore.getType(); + Iterator<IKeyStoreEntry> iterator2 = keys.iterator(); + while ((iterator2 != null) && (iterator2.hasNext())) + { + EntryNode keyEntry = (EntryNode) iterator2.next(); + entries.add(keyEntry.getId()); + } + + } + + } + catch (KeyStoreManagerException e) + { + StudioLogger.error(this.getClass(), "Error retrieving keys from keystore", e); //$NON-NLS-1$ + } + + } + catch (InvalidPasswordException e) + { + setErrorMessage(CertificateManagerNLS.ConvertKeyStoreTypeDialog_Invalid_Keystore_Pass); + this.keystorePassword.setText(""); //$NON-NLS-1$ + this.keystorePassword.setFocus(); //select the password text box so the user can retype the password + } + } + + return entries.toArray(new String[0]); + } + + /** + * Fill the key entries combo + * + */ + private void setKeyEntries() + { + setErrorMessage(null); + + String keystoreSelected = keystoreCombo.getItem(keystoreCombo.getSelectionIndex()); + + this.selectedKeystore = (IKeyStore) keystoreCombo.getData(keystoreSelected); + String[] availableKeys = getAvailableEntriesForKeystore(this.selectedKeystore); + + if (availableKeys.length > 0) + { + keysCombo.setItems(availableKeys); + int selectedEntryIndex = 0; + + if (initialSelectedEntry != null) + { + selectedEntryIndex = keysCombo.indexOf(initialSelectedEntry.getAlias()); + initialSelectedEntry = null; //the selectedEntry only serves as first selection + } + + keysCombo.select(selectedEntryIndex > 0 ? selectedEntryIndex : 0); + + updatePageComplete(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.motorola.studio.android.packaging.ui.wizards.RemoveExternalPackageSignaturePage + * #createExtendedArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createExtendedArea(Composite parent) + { + GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + + // Keystore label + this.keystoreLabel = new Label(parent, SWT.NONE); + this.keystoreLabel.setText(CertificateManagerNLS.SIGN_WIZARD_AREA_SIGN_KEYSTORE_LABEL); + this.keystoreLabel.setLayoutData(layoutData); + + // Keystore combo + this.keystoreCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.SINGLE); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1); + this.keystoreCombo.setLayoutData(layoutData); + keystoreCombo.addSelectionListener(new SelectionAdapter() + { + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) + { + keystorePassword.setText(""); //$NON-NLS-1$ + keystorePassword.setEnabled(true); + savePassword.setSelection(false); + savePassword.setEnabled(false); + loadKeystore.setEnabled(false); + keysCombo.removeAll(); + setKeyEntries(); + if (keystorePassword.getEnabled()) + { + keystorePassword.setFocus(); + } + //it only serves as + initialSelectedKeyStore = null; + } + + }); + + // Keystore password label + Label keystorePasswordLabel = new Label(parent, SWT.NONE); + keystorePasswordLabel + .setText(CertificateManagerNLS.CreateKeystorePage_KeystorePasswordLabel); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + keystorePasswordLabel.setLayoutData(layoutData); + + // Keystore password combo + this.keystorePassword = new Text(parent, SWT.BORDER | SWT.PASSWORD); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1); + this.keystorePassword.setLayoutData(layoutData); + this.keystorePassword.addListener(SWT.Modify, new Listener() + { + @Override + public void handleEvent(Event event) + { + if (keystorePassword.getText().isEmpty()) + { + loadKeystore.setEnabled(false); + savePassword.setEnabled(false); + } + else + { + loadKeystore.setEnabled(true); + savePassword.setEnabled(true); + } + keysCombo.removeAll(); + updatePageComplete(); + } + }); + this.keystorePassword.addSelectionListener(loadKeysSelectionAdapter); + + // Load key entries Button + this.loadKeystore = new Button(parent, SWT.PUSH); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + this.loadKeystore.setLayoutData(layoutData); + this.loadKeystore.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_LOAD); + this.loadKeystore.setEnabled(false); + this.loadKeystore.addSelectionListener(loadKeysSelectionAdapter); + + // Save Keystore Password checkbox + this.savePassword = new Button(parent, SWT.CHECK); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1); + this.savePassword.setLayoutData(layoutData); + this.savePassword.setText(CertificateManagerNLS.PasswordProvider_SaveThisPassword); + this.savePassword.setEnabled(false); + this.savePassword.setSelection(false); + + // key entry label + this.keysLabel = new Label(parent, SWT.NONE); + this.keysLabel.setText(CertificateManagerNLS.SIGN_WIZARD_AREA_SIGN_KEYS_LABEL); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); + this.keysLabel.setLayoutData(layoutData); + + // key entry combo + this.keysCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.SINGLE); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1); + this.keysCombo.setLayoutData(layoutData); + + PlatformUI + .getWorkbench() + .getHelpSystem() + .setHelp(parent, + CertificateManagerActivator.SIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID); + + populateKeyStoreCombo(); + } + + @Override + protected void createPackageTreeLabel() + { + GridData layoutData; + Label packagesLabel = new Label(this.mainComposite, SWT.NONE); + packagesLabel.setText(CertificateManagerNLS.SignExternalPackagePage_Package_Tree_Label); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1); + packagesLabel.setLayoutData(layoutData); + } + + protected void populateKeyStoreCombo() + { + HashMap<String, IKeyStore> availableKeystores = getAvailableKeystores(); + if (availableKeystores.size() > 0) + { + + for (String keystoreKey : availableKeystores.keySet()) + { + IKeyStore newKeystore = availableKeystores.get(keystoreKey); + this.keystoreCombo.setData(keystoreKey, availableKeystores.get(keystoreKey)); + this.keystoreCombo.add(newKeystore.toString()); + + if (initialSelectedKeyStore != null) + { + if (initialSelectedKeyStore.equals(newKeystore)) + { + //select combo with the item selected in Signing and keys view + keystoreCombo.select(keystoreCombo.indexOf(newKeystore.toString())); + setKeyEntries(); + } + } + } + + if (initialSelectedKeyStore == null) + { + this.keystoreCombo.select(0); + } + } + } + + /** + * + * @return the key entry selected by user + */ + public IKeyStoreEntry getSelectedKeyEntry() + { + IKeyStoreEntry result = null; + try + { + result = + this.selectedKeystore.getEntry( + this.keysCombo.getItem(this.keysCombo.getSelectionIndex()), + getKeystorePassword()); + } + catch (KeyStoreManagerException e) + { + // should never happen + StudioLogger.error("Could not retrieve entry while signing package"); //$NON-NLS-1$ + } + catch (InvalidPasswordException e) + { + // should never happen + StudioLogger.error("Invalid password while retrieving entry to sign package"); //$NON-NLS-1$ + } + + return result; + } + + /** + * + * @return the keystore selected by user + */ + public IKeyStore getSelectedKeyStore() + { + return this.selectedKeystore; + } + + /** + * + * @return the keystore password entered by user + */ + public String getKeystorePassword() + { + return this.keystorePassword.getText(); + } + + /** + * + * @return key entry password + */ + public String getKeyEntryPassword() + { + + try + { + this.keyEntryPassword = + pP.getPassword(this.keysCombo.getItem(this.keysCombo.getSelectionIndex()), true); + } + catch (KeyStoreManagerException e) + { + StudioLogger.error(this.getClass(), "Error retrieving keys entry password", e); //$NON-NLS-1$ + } + return this.keyEntryPassword; + } + + public PasswordProvider getPasswordProvider() + { + return pP; + } + + /** + * + * @return the keystore type + */ + public String getKeyStoreType() + { + return this.keyStoreType; + } + + /** + * Update the page status, validating each field of this page The basic + * validation is made by superclass + */ + @Override + public void updatePageComplete() + { + super.updatePageComplete(); + int severity = getMessageType(); + String messageAux = severity == IMessageProvider.NONE ? null : getMessage(); + + if (messageAux == null) + { + if (!(((this.keystoreCombo != null) && (this.keystoreCombo.getItemCount() > 0) + && (this.keystoreCombo.getItem(this.keystoreCombo.getSelectionIndex()) != null) && !this.keystoreCombo + .getItem(this.keystoreCombo.getSelectionIndex()).equalsIgnoreCase("")) && ((this.keysCombo != null) //$NON-NLS-1$ + && (this.keysCombo.getItemCount() > 0) + && (this.keysCombo.getItem(this.keysCombo.getSelectionIndex()) != null) && !this.keysCombo + .getItem(this.keysCombo.getSelectionIndex()).equalsIgnoreCase("")))) //$NON-NLS-1$ + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_NO_CERTIFICATE_ERROR; + severity = IMessageProvider.ERROR; + } + + if (messageAux == null) + { + messageAux = + + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION; + severity = IMessageProvider.NONE; + } + + setMessage(messageAux, severity); + setPageComplete(severity == IMessageProvider.NONE); + } + + } + + /** + * @return checkbox save password + */ + public boolean getSavePasswordSelection() + { + return this.savePassword.getSelection(); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java new file mode 100644 index 0000000..ca9541f --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/ui/wizards/SignExternalPackageWizard.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.ui.wizards; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.security.UnrecoverableKeyException; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarFile; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyOperation; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; +import com.motorolamobility.studio.android.certmanager.packaging.PackageFile; +import com.motorolamobility.studio.android.certmanager.packaging.sign.PackageFileSigner; +import com.motorolamobility.studio.android.certmanager.packaging.sign.SignException; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore; +import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStoreEntry; + +/** + * This Wizard signs a package. based on a root dir, It shows a list o packages + * to sign and let user choose a certificate to use + */ +public class SignExternalPackageWizard extends Wizard +{ + private SignExternalPackagePage page = null; + + public SignExternalPackageWizard(IStructuredSelection selection, IKeyStore selectedKeyStore) + { + this(selection, selectedKeyStore, null); + } + + public SignExternalPackageWizard(IStructuredSelection selection, IKeyStore selectedKeyStore, + IKeyStoreEntry selectedEntry) + { + setWindowTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE); + setNeedsProgressMonitor(true); + setHelpAvailable(false); + this.page = + new SignExternalPackagePage("signPage", selection, selectedKeyStore, selectedEntry); + setDefaultPageImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin( + CertificateManagerActivator.PLUGIN_ID, + CertificateManagerActivator.SIGNATURE_WIZ_BAN)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.wizard.Wizard#addPages() + */ + @Override + public void addPages() + { + addPage(this.page); + } + + /** + * Finishes this wizard, signing the selected packages + */ + @Override + public boolean performFinish() + { + final List<String> defectivePackages = new ArrayList<String>(); + IRunnableWithProgress finishAction = new IRunnableWithProgress() + { + + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException + { + List<String> selectedFiles = + SignExternalPackageWizard.this.page.getSelectedPackages(); + monitor.beginTask(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE, + selectedFiles.size() * 2); + for (String selected : selectedFiles) + { + File file = new File(selected); + monitor.setTaskName(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_OPERATION + + " " + file.getName()); + if ((file != null) && file.exists() && file.isFile() && file.canWrite()) + { + OutputStream fileToWrite = null; + PackageFile pack = null; + JarFile jar = null; + try + { + + // Update monitor + monitor.worked(1); + monitor.setTaskName(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_OPERATION + + " " + file.getName()); + + String keyStorePassword = + SignExternalPackageWizard.this.page.getKeystorePassword(); + if (SignExternalPackageWizard.this.page.getSavePasswordSelection()) + { + SignExternalPackageWizard.this.page.getPasswordProvider() + .saveKeyStorePassword(keyStorePassword); + } + String keyEntryPassword = + SignExternalPackageWizard.this.page.getKeyEntryPassword(); + boolean keepTrying; + if (keyEntryPassword != null) + { + keepTrying = true; + } + else + { + keepTrying = false; + throw new Exception(); + } + while (keepTrying) + { + try + { + // Open package and remove signature + jar = new JarFile(file); + pack = new PackageFile(jar); + pack.removeMetaEntryFiles(); + + // Sign the new package + PackageFileSigner.signPackage(pack, + SignExternalPackageWizard.this.page + .getSelectedKeyEntry(), keyEntryPassword, + PackageFileSigner.MOTODEV_STUDIO); + keepTrying = false; + } + catch (UnrecoverableKeyException sE) + { + keyEntryPassword = + SignExternalPackageWizard.this.page + .getPasswordProvider().getPassword( + SignExternalPackageWizard.this.page + .getSelectedKeyEntry() + .getAlias(), true, false); + if (keyEntryPassword == null) + { + keepTrying = false; + } + else + { + keepTrying = true; + } + } + } + + // Write the new package file + fileToWrite = new FileOutputStream(file); + pack.write(fileToWrite); + PackageFile.zipAlign(file); + } + catch (IOException e) + { + defectivePackages.add(selected); + StudioLogger.error( + SignExternalPackageWizard.class.toString(), + "Impossible write to package: " + selected + " " + + e.getMessage()); + } + catch (SignException e) + { + defectivePackages.add(selected); + StudioLogger.error( + SignExternalPackageWizard.class.toString(), + "Impossible sign the package: " + selected + " " + + e.getMessage()); + } + catch (SecurityException e) + { + defectivePackages.add(selected); + StudioLogger.error( + SignExternalPackageWizard.class.toString(), + "Impossible sign the package: " + selected + " " + + e.getMessage()); + } + catch (Exception e) + { + defectivePackages.add(selected); + StudioLogger.error( + SignExternalPackageWizard.class.toString(), + "Impossible sign the package: " + selected + " " + + e.getMessage()); + } + finally + { + System.gc(); // Force garbage collector to avoid + // errors when deleting temp files + + try + { + if (pack != null) + { + pack.removeTemporaryEntryFiles(); + } + + if (fileToWrite != null) + { + fileToWrite.close(); + } + + if (jar != null) + { + jar.close(); + } + } + catch (IOException e) + { + // Silent exception. Only log the deletion + // exception. + StudioLogger.error(CertificateManagerActivator.PLUGIN_ID, + "Deleting temporary files"); + } + } + } + else + { + defectivePackages.add(selected); + } + monitor.worked(1); + } + monitor.done(); + } + + }; + + try + { + PlatformUI.getWorkbench().getProgressService() + .runInUI(new ProgressMonitorDialog(getShell()), finishAction, null); + } + catch (InvocationTargetException e1) + { + StudioLogger.error(SignExternalPackageWizard.class.toString(), + "Error running finish actions"); + } + catch (InterruptedException e1) + { + StudioLogger.error(SignExternalPackageWizard.class.toString(), + "Error running finish actions"); + } + + if (ResourcesPlugin.getWorkspace().getRoot().getLocation() + .isPrefixOf(this.page.getSourcePath())) + { + WorkspaceModifyOperation op = new WorkspaceModifyOperation() + { + + @Override + protected void execute(IProgressMonitor monitor) throws CoreException, + InvocationTargetException, InterruptedException + { + for (IContainer container : ResourcesPlugin + .getWorkspace() + .getRoot() + .findContainersForLocation( + SignExternalPackageWizard.this.page.getSourcePath())) + { + + container.refreshLocal(IResource.DEPTH_INFINITE, monitor); + } + + } + + }; + try + { + PlatformUI.getWorkbench().getProgressService().run(false, false, op); + } + catch (InvocationTargetException e) + { + StudioLogger.error(SignExternalPackageWizard.class.toString(), + "Error refreshing workspace"); + } + catch (InterruptedException e) + { + StudioLogger.error(SignExternalPackageWizard.class.toString(), + "Error refreshing workspace"); + } + } + if (!defectivePackages.isEmpty()) + { + MultiStatus errors = + new MultiStatus(CertificateManagerActivator.PLUGIN_ID, IStatus.ERROR, + CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_ERROR_REASON, null); + for (String defect : defectivePackages) + { + errors.add(new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, defect)); + } + + ErrorDialog errorBox = + new ErrorDialog(getShell(), + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE, + CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_ERROR, errors, + IStatus.ERROR); + errorBox.open(); + } + return true; + + } + + @Override + public void createPageControls(Composite pageContainer) + { + super.createPageControls(pageContainer); + PlatformUI + .getWorkbench() + .getHelpSystem() + .setHelp(getShell(), + CertificateManagerActivator.SIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID); + } +} diff --git a/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java new file mode 100644 index 0000000..2cd4988 --- /dev/null +++ b/src/plugins/certmanager/src/com/motorolamobility/studio/android/certmanager/views/KeystoreManagerView.java @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 com.motorolamobility.studio.android.certmanager.views; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; + +import com.motorola.studio.android.common.log.StudioLogger; +import com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener; +import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent; +import com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEventManager; +import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException; +import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS; +import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode; +import com.motorolamobility.studio.android.certmanager.ui.model.KeyStoreRootNode; +import com.motorolamobility.studio.android.certmanager.ui.model.SigningAndKeysModelManager; +import com.motorolamobility.studio.android.certmanager.ui.tree.ExpiresInColumnLabelProvider; +import com.motorolamobility.studio.android.certmanager.ui.tree.KeystoreManagerTreeContentProvider; +import com.motorolamobility.studio.android.certmanager.ui.tree.LastBackupDateColumnLabelProvider; +import com.motorolamobility.studio.android.certmanager.ui.tree.NameAliasColumnLabelProvider; +import com.motorolamobility.studio.android.certmanager.ui.tree.PathColumnLabelProvider; +import com.motorolamobility.studio.android.certmanager.ui.tree.TypeColumnLabelProvider; + +/** + * View to manage certificates under MOTODEV Studio for Android + */ +public class KeystoreManagerView extends ViewPart implements IKeyStoreModelListener +{ + /** + * The ID of the view as specified by the extension. + */ + public static final String ID = "com.motorola.studio.android.packaging.ui.signingview"; //$NON-NLS-1$ + + private TreeViewer viewer; + + /** + * This is a callback that will allow us + * to create the viewer and initialize it. + */ + @Override + public void createPartControl(Composite parent) + { + viewer = + new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER + | SWT.FULL_SELECTION | SWT.VIRTUAL | SWT.MULTI); //Virtual is required due to ILazyTreeContentProvider + viewer.setUseHashlookup(true); + viewer.setAutoExpandLevel(0); + + viewer.setContentProvider(new KeystoreManagerTreeContentProvider(viewer)); + viewer.setInput(getInitalInput()); + viewer.expandToLevel(getInitalInput(), 1); + ColumnViewerToolTipSupport.enableFor(viewer); + + getSite().setSelectionProvider(viewer); + + Tree tree = viewer.getTree(); + tree.setLinesVisible(true); + tree.setHeaderVisible(true); + tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); + { + TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE); + treeViewerColumn.setLabelProvider(new NameAliasColumnLabelProvider()); + TreeColumn trclmnNewColumn = treeViewerColumn.getColumn(); + trclmnNewColumn.setWidth(250); + trclmnNewColumn + .setText(CertificateManagerNLS.CertificateManagerView_NameAlias_ColumnName); + + tree.setSortColumn(treeViewerColumn.getColumn()); + tree.setSortDirection(SWT.DOWN); + } + { + TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE); + treeViewerColumn.setLabelProvider(new TypeColumnLabelProvider()); + TreeColumn trclmnNewColumn = treeViewerColumn.getColumn(); + trclmnNewColumn.setWidth(75); + trclmnNewColumn.setText(CertificateManagerNLS.CertificateManagerView_Type_ColumnName); + } + { + TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE); + treeViewerColumn.setLabelProvider(new ExpiresInColumnLabelProvider()); + TreeColumn trclmnExpiresIn = treeViewerColumn.getColumn(); + trclmnExpiresIn.setWidth(100); + trclmnExpiresIn + .setText(CertificateManagerNLS.CertificateManagerView_ExpiresIn_ColumnName); + } + { + TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.NONE); + treeViewerColumn.setLabelProvider(new LastBackupDateColumnLabelProvider()); + TreeColumn trclmnLastBackupDate = treeViewerColumn.getColumn(); + trclmnLastBackupDate.setWidth(125); + trclmnLastBackupDate + .setText(CertificateManagerNLS.CertificateManagerView_LastBackupDate_ColumnName); + } + { + TreeViewerColumn treeViewerColumn = new TreeViewerColumn(viewer, SWT.LEFT); + treeViewerColumn.setLabelProvider(new PathColumnLabelProvider()); + TreeColumn trclmnPath = treeViewerColumn.getColumn(); + trclmnPath.setWidth(500); + trclmnPath.setText(CertificateManagerNLS.CertificateManagerView_Path_ColumnName); + } + + // Create the help context id for the viewer's control + PlatformUI + .getWorkbench() + .getHelpSystem() + .setHelp(viewer.getControl(), + "com.motorolamobility.studio.android.certmanager.viewer"); //$NON-NLS-1$ + + hookContextMenu(); + + getSite().setSelectionProvider(viewer); + + //register listener for model changes + KeyStoreModelEventManager.getInstance().addListener(this); + } + + private void hookContextMenu() + { + MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() + { + @Override + public void menuAboutToShow(IMenuManager manager) + { + fillContextMenu(manager); + } + }); + Menu menu = menuMgr.createContextMenu(viewer.getControl()); + viewer.getControl().setMenu(menu); + getSite().registerContextMenu(menuMgr, viewer); + } + + private void fillContextMenu(IMenuManager manager) + { + // Other plug-ins can contribute there actions here + // manager.add(openClose); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + /** + * Loads the keystores from preference and <user_home>\motodevstudio\tools\motodev.keystore + * @return root node (invisible) that contains as children the keystores. + */ + private Object getInitalInput() + { + return SigningAndKeysModelManager.getInstance().getKeyStoresRootNode(); + } + + /** + * Passing the focus request to the viewer's control. + */ + @Override + public void setFocus() + { + viewer.getControl().setFocus(); + } + + public TreeViewer getTreeViewer() + { + return viewer; + } + + /** + * Closing the view + */ + @Override + public void dispose() + { + super.dispose(); + //remove listener for model changes + KeyStoreModelEventManager.getInstance().removeListener(this); + } + + /* (non-Javadoc) + * @see com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener#handleNodeAdditionEvent(com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent) + */ + @Override + public void handleNodeAdditionEvent(final KeyStoreModelEvent keyStoreModeEvent) + { + Display display = Display.getDefault(); + if (!display.isDisposed()) + { + display.syncExec(new Runnable() + { + @Override + public void run() + { + ITreeNode treeNodeItem = keyStoreModeEvent.getTreeNodeItem(); + ITreeNode parentNode = treeNodeItem.getParent(); + + /* (parentNode instanceof KeyStoreRootNode) is a workaround to add nodes to the root node + * since getTreeViewer().getExpandedState(parentNode) always return false when the parentNode + * is the root node (KeyStoreRootNode in this case) + */ + if (getTreeViewer().getExpandedState(parentNode) + || (parentNode instanceof KeyStoreRootNode)) + { + getTreeViewer().add(parentNode, treeNodeItem); + } + else + { + List<ITreeNode> children; + try + { + children = parentNode.getChildren(); + } + catch (KeyStoreManagerException e) + { + children = Collections.emptyList(); + } + + if (children.size() > 0) + { + getTreeViewer().setChildCount(parentNode, children.size()); + } + } + } + }); + } + } + + /* (non-Javadoc) + * @see com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener#handleNodeRemovalEvent(com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent) + */ + @Override + public void handleNodeRemovalEvent(final KeyStoreModelEvent keyStoreModeEvent) + { + Display display = Display.getDefault(); + if (!display.isDisposed()) + { + display.syncExec(new Runnable() + { + @Override + public void run() + { + if (!getTreeViewer().getTree().isDisposed()) + { + getTreeViewer().remove(keyStoreModeEvent.getTreeNodeItem()); + } + } + }); + } + } + + /* (non-Javadoc) + * @see com.motorolamobility.studio.android.certmanager.event.IKeyStoreModelListener#handleNodeUpdateEvent(com.motorolamobility.studio.android.certmanager.event.KeyStoreModelEvent) + */ + @Override + public void handleNodeUpdateEvent(final KeyStoreModelEvent keyStoreModeEvent) + { + Display display = Display.getDefault(); + if (!display.isDisposed()) + { + display.asyncExec(new Runnable() + { + @Override + public void run() + { + ITreeNode treeNode = keyStoreModeEvent.getTreeNodeItem(); + getTreeViewer().update(treeNode, null); + } + }); + } + } + + @Override + public void handleNodeCollapseEvent(final KeyStoreModelEvent keyStoreModelEvent) + { + Display display = Display.getDefault(); + if (!display.isDisposed()) + { + display.asyncExec(new Runnable() + { + @Override + public void run() + { + ITreeNode treeNode = keyStoreModelEvent.getTreeNodeItem(); + //Ugly workaround to avoid JFace treeViewer to enter in a infinite loop asking for children all the time. + getTreeViewer().remove(treeNode); + getTreeViewer().add(treeNode.getParent(), treeNode); + } + }); + } + } + + @Override + public void handleNodeRefreshEvent(final KeyStoreModelEvent keyStoreModelEvent) + { + Display display = Display.getDefault(); + if (!display.isDisposed()) + { + display.asyncExec(new Runnable() + { + @Override + public void run() + { + ITreeNode treeNode = keyStoreModelEvent.getTreeNodeItem(); + if (treeNode != null) + { + try + { + getTreeViewer().remove(treeNode, treeNode.getChildren().toArray()); + } + catch (KeyStoreManagerException e) + { + StudioLogger.error("Error while accessing keystore manager. " + + e.getMessage()); + } + + getTreeViewer().refresh(treeNode, true); + } + } + }); + } + } + + @Override + public void handleNodeClearEvent(final KeyStoreModelEvent keyStoreModelEvent) + { + Display display = Display.getDefault(); + if (!display.isDisposed()) + { + display.syncExec(new Runnable() + { + @Override + public void run() + { + ITreeNode treeNode = keyStoreModelEvent.getTreeNodeItem(); + if (treeNode != null) + { + try + { + getTreeViewer().remove(treeNode, treeNode.getChildren().toArray()); + getTreeViewer().setChildCount(treeNode, 0); + } + catch (KeyStoreManagerException e) + { + StudioLogger.error("Error while accessing keystore manager. " + + e.getMessage()); + } + } + } + }); + } + } +}
\ No newline at end of file |