package com.mobilesorcery.sdk.core;
import java.security.SecureRandom;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.IdentityHashMap;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
/**
* <p>A simple security solution for projects that needs access
* to vital system resources.</p>
* <p>A special token is created for the project as well as the workspace,
* and only if they match will privileged access be granted.</p>
* <p>An obvious attack would be that B requests a project from W with this
* special token and then resends an updated project with malicious code to W. However,
* this is not meant to cover every security aspect but just to make sure
* that there is <i>some</i> protection for the user from inadvertently downloading
* a project from somewhere off the Internet that contains evil, nasty scripts.
* We conjecture that most people wouldn't expect that kind of code to run just because
* we imported an Eclipse project!</p>
* @author Mattias Bybro
*
*/
public class PrivilegedAccess {
private static final String PRIVILEGED_ACCESS_TOKEN = "privileged.access.token";
private static final PrivilegedAccess INSTANCE = new PrivilegedAccess();
private boolean blanketAccess;
private SecureRandom rnd;
private PrivilegedAccess() {
blanketAccess = CoreMoSyncPlugin.isHeadless() && Arrays.asList(Platform.getApplicationArgs()).contains("-allow-scripts:true");
rnd = new SecureRandom();
}
public static PrivilegedAccess getInstance() {
return INSTANCE;
}
public void assertAccess(MoSyncProject project) throws CoreException {
if (!hasAccess(project)) {
if (CoreMoSyncPlugin.isHeadless()) {
throw new CoreException(new Status(IStatus.ERROR, CoreMoSyncPlugin.PLUGIN_ID,
MessageFormat.format("Script execution not allowed for project {0}. For headless builds, set the command line parameter \"-allow-scripts:true\"", project.getName())));
} else {
throw new CoreException(new Status(IStatus.ERROR, CoreMoSyncPlugin.PLUGIN_ID,
MessageFormat.format("Script execution not allowed for project {0}. Change this in Window > Preferences > MoSync Tool > Scripts", project.getName())));
}
}
}
public boolean hasAccess(MoSyncProject project) {
if (blanketAccess) {
return true;
}
String prefName = computePrefName(project);
String token = CoreMoSyncPlugin.getDefault().getPreferenceStore().getString(prefName);
String projectToken = project.getProperty(PRIVILEGED_ACCESS_TOKEN);
boolean result = token != null && token.equals(projectToken);
if (!result) {
// If we have different tokens just clear them
ungrant(project);
}
return result;
}
public void grantAccess(MoSyncProject project, boolean grant) {
if (hasAccess(project) ^ grant) {
if (grant) {
grant(project);
} else {
ungrant(project);
}
}
}
private void ungrant(MoSyncProject project) {
String prefName = computePrefName(project);
project.initProperty(PRIVILEGED_ACCESS_TOKEN, null, MoSyncProject.LOCAL_PROPERTY, true);
CoreMoSyncPlugin.getDefault().getPreferenceStore().setToDefault(prefName);
}
private void grant(MoSyncProject project) {
byte[] token = new byte[16];
rnd.nextBytes(token);
String tokenStr = Util.toBase16(token);
project.initProperty(PRIVILEGED_ACCESS_TOKEN, tokenStr, MoSyncProject.LOCAL_PROPERTY, true);
String prefName = computePrefName(project);
CoreMoSyncPlugin.getDefault().getPreferenceStore().setValue(prefName, tokenStr);
}
private String computePrefName(MoSyncProject project) {
return "privileged.access" + ":" + project.getName();
}
}