/* * 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; } }