/******************************************************************************* * Copyright (c) 2015, 2016 Red Hat Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat - Initial Contribution *******************************************************************************/ package org.eclipse.linuxtools.internal.vagrant.core; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.security.storage.ISecurePreferences; import org.eclipse.equinox.security.storage.SecurePreferencesFactory; import org.eclipse.equinox.security.storage.StorageException; /** * A class for managing the environments of various vagrant boxes. * * The implementation will use secure storage to save the environments for all * environments. It will keep all environments stored in one property key, * serialized, and load / store via a byte array. * * While it's definitely possible that some environments do not need to be * secured, it seems prudent in this case that the possibility that credentials * will be passed through the environment make it more than reasonable to secure * all environments. */ public class EnvironmentsManager { private static EnvironmentsManager singleton = new EnvironmentsManager(); public static EnvironmentsManager getSingleton() { return singleton; } private EnvironmentsManager() { getEnvironment(); // pre-load from preferences } private Environment env; private synchronized Environment getEnvironment() { if (env == null) env = new Environment(); return env; } private class Environment { private static final String ENVIRONMENT_ATTRIBUTE = "org.eclipse.linuxtools.internal.vagrant.core.EnvironmentsManager.EnvironmentKey"; //$NON-NLS-1$ private static final String SECURE_PREFERNCES_BASEKEY = Activator.PLUGIN_ID; private static final String ENVIRONMENT_KEY = "environment"; //$NON-NLS-1$ private static final boolean READ = true; private static final boolean WRITE = false; private Map<String, Map<String, String>> backing; public Environment() { load(); } private ISecurePreferences getPreferenceNode() { ISecurePreferences root = SecurePreferencesFactory.getDefault(); ISecurePreferences node = root.node(SECURE_PREFERNCES_BASEKEY); return node.node(ENVIRONMENT_KEY); } @SuppressWarnings("unchecked") private void load() { ISecurePreferences prefs2 = getPreferenceNode(); try { byte[] read = prefs2.getByteArray(ENVIRONMENT_ATTRIBUTE, (byte[]) null); backing = new HashMap<>(); if (read == null) { return; } ByteArrayInputStream bis = new ByteArrayInputStream(read); ObjectInputStream ois = new ObjectInputStream(bis); backing = (Map<String, Map<String, String>>) ois.readObject(); ois.close(); bis.close(); } catch (IOException ioe) { Activator.getDefault().getLog().log(createStatus(ioe, READ)); } catch (ClassNotFoundException cnfe) { Activator.getDefault().getLog().log(createStatus(cnfe, READ)); } catch (StorageException se) { Activator.getDefault().getLog().log(createStatus(se, READ)); } } private void save() { if (backing == null) { backing = new HashMap<>(); } ISecurePreferences prefs = getPreferenceNode(); try { byte[] toSave = null; ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(backing); oos.close(); bos.close(); toSave = bos.toByteArray(); prefs.putByteArray(ENVIRONMENT_ATTRIBUTE, toSave, true); prefs.flush(); } catch (IOException ioe) { Activator.getDefault().getLog().log(createStatus(ioe, WRITE)); } catch (StorageException se) { Activator.getDefault().getLog().log(createStatus(se, WRITE)); } } private IStatus createStatus(Throwable t, boolean action) { // TODO externalize? if (action == READ) return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.EnvironmentsManager_error_read, t); else return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.EnvironmentsManager_error_write, t); } public void setEnvironmentForFolder(File folder, Map<String, String> env) { if (backing != null) { backing.put(folder.getAbsolutePath(), env); } } public Map<String, String> getEnvironmentForFolder(File folder) { if (backing != null) { return backing.get(folder.getAbsolutePath()); } return null; } } public Map<String, String> getEnvironment(File folder) { return getEnvironment().getEnvironmentForFolder(folder); } public void setEnvironment(File folder, Map<String, String> environment) { Environment env = getEnvironment(); env.setEnvironmentForFolder(folder, environment); env.save(); } /* * Convert a string/string hashmap into an array of string environment * variables as required by java.lang.Runtime This will super-impose the * provided environment variables ON TOP OF the existing environment in * eclipse, as users may not know *all* environment variables that need to * be set, or to do so may be tedious. */ public static String[] convertEnvironment(final Map<String, String> env) { // Create a new map based on pre-existing environment of Eclipse final Map<String, String> environment = System.getenv(); Map<String, String> result = new HashMap<>(environment); // Add all new environments on top of existing if (env != null) { result.putAll(env); } // also update the PATH to include the path to the Vagrant executable final StringBuilder path = new StringBuilder(); final String newEnvPath = path.append(environment.get("PATH")) //$NON-NLS-1$ .append(File.pathSeparator) .append(VagrantConnection.getUserDefinedVagrantPath()) .toString(); result.put("PATH", newEnvPath); //$NON-NLS-1$ // Convert the combined map into a form that can be used to launch // process ArrayList<String> ret = new ArrayList<>(); Iterator<String> it = result.keySet().iterator(); String working = null; while (it.hasNext()) { working = it.next(); ret.add(working + "=" + result.get(working)); //$NON-NLS-1$ } return ret.toArray(new String[ret.size()]); } }