package com.mobilesorcery.sdk.internal;
import java.security.GeneralSecurityException;
import java.text.MessageFormat;
import javax.crypto.spec.PBEKeySpec;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.security.storage.SecurePreferencesFactory;
import org.eclipse.equinox.security.storage.StorageException;
import org.eclipse.jface.preference.IPreferenceStore;
import com.mobilesorcery.sdk.core.CoreMoSyncPlugin;
import com.mobilesorcery.sdk.core.IProvider;
import com.mobilesorcery.sdk.core.MoSyncProject;
import com.mobilesorcery.sdk.core.Util;
// Consider refactoring this into two classes.
public class SecurePasswordProvider implements IProvider<PBEKeySpec, String> {
private static final String SECURE_ROOT_NODE = "mosync.com";
private static final String LOCAL_KEYRING_MASTER_KEY = "master.passkey";
private static final String USE_ECLIPSE_SECURE_PREFS = "use.eclipse.secure.prefs";
private static final String INSECURE_MASTER_KEY = "insecure.master.key";
@Override
public PBEKeySpec get(String key) {
try {
if (usesEclipseSecureStorage()) {
String masterKey = SecurePreferencesFactory.getDefault().node(SECURE_ROOT_NODE).get(LOCAL_KEYRING_MASTER_KEY, "");
if (Util.isEmpty(masterKey)) {
masterKey = createMasterKey();
SecurePreferencesFactory.getDefault().node(SECURE_ROOT_NODE).put(LOCAL_KEYRING_MASTER_KEY, masterKey, true);
}
return new PBEKeySpec(masterKey.toCharArray());
} else {
// Do not encrypt
return null;
}
} catch (Exception e) {
CoreMoSyncPlugin.getDefault().log(e);
return null;
}
}
public boolean usesEclipseSecureStorage() {
IPreferenceStore prefs = CoreMoSyncPlugin.getDefault().getPreferenceStore();
return prefs.getBoolean(USE_ECLIPSE_SECURE_PREFS);
}
public void doUseEclipseSecureStorage(boolean useEclipseSecureStorage) throws CoreException {
boolean changed = useEclipseSecureStorage != usesEclipseSecureStorage();
if (changed) {
clearMasterPassword();
IPreferenceStore prefs = CoreMoSyncPlugin.getDefault().getPreferenceStore();
prefs.setValue(USE_ECLIPSE_SECURE_PREFS, useEclipseSecureStorage);
resetMasterPassword();
}
}
private void clearMasterPassword() {
CoreMoSyncPlugin.getDefault().getLog().log(new Status(IStatus.INFO, CoreMoSyncPlugin.PLUGIN_ID, "Resetting (MoSync) master password."));
// Reset the password, but only of the currently used password provider type.
if (usesEclipseSecureStorage()) {
SecurePreferencesFactory.getDefault().node(SECURE_ROOT_NODE).remove(LOCAL_KEYRING_MASTER_KEY);
} else {
CoreMoSyncPlugin.getDefault().getPreferenceStore().setToDefault(INSECURE_MASTER_KEY);
}
}
private void resetMasterPassword() throws CoreException {
MultiStatus result = new MultiStatus(CoreMoSyncPlugin.PLUGIN_ID, IStatus.OK, "Resetting master password failed for some projects.", null);
resetMasterPassword(ResourcesPlugin.getWorkspace().getRoot(), result);
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
resetMasterPassword(project, result);
}
if (result.getChildren().length > 0) {
CoreMoSyncPlugin.getDefault().getLog().log(result);
throw new CoreException(result);
}
}
private void resetMasterPassword(IResource resource, MultiStatus status) {
String resourceName = "";
try {
switch (resource.getType()) {
case IResource.ROOT:
CoreMoSyncPlugin.getDefault().getSecureProperties().resetMasterPassword(this);
resourceName = "workspace";
break;
case IResource.PROJECT:
IProject project = (IProject) resource;
if (project.isOpen()) {
MoSyncProject mosyncProject = MoSyncProject.create(project);
mosyncProject.getSecurePropertyOwner().resetMasterPassword(this);
}
resourceName = project.getName();
break;
}
} catch (Exception e) {
status.add(new Status(IStatus.ERROR, CoreMoSyncPlugin.PLUGIN_ID, MessageFormat.format("Could not reset master password for: {0}", resourceName), e));
}
}
private String createMasterKey() throws GeneralSecurityException, StorageException {
String masterKey = SecureProperties.generateRandomKey();
return masterKey;
}
}