use of net.i2p.util.SecureDirectory in project i2p.i2p by i2p.
the class WebAppStarter method startWebApp.
/**
* Adds and starts.
* Prior to 0.9.28, was not guaranteed to throw on failure.
* Not for routerconsole.war, it's started in RouterConsoleRunner.
*
* @throws Exception just about anything, caller would be wise to catch Throwable
* @since public since 0.9.33, was package private
*/
public static void startWebApp(RouterContext ctx, ContextHandlerCollection server, String appName, String warPath) throws Exception {
File tmpdir = new SecureDirectory(ctx.getTempDir(), "jetty-work-" + appName + ctx.random().nextInt());
WebAppContext wac = addWebApp(ctx, server, appName, warPath, tmpdir);
// _log.debug("Loading war from: " + warPath);
LocaleWebAppHandler.setInitParams(wac, INIT_PARAMS);
// default false, set to true so we get good logging,
// and the caller will know it failed
wac.setThrowUnavailableOnStartupException(true);
wac.start();
// Doesn't have to be right, just for presence indication
int port = ctx.portMapper().getPort(PortMapper.SVC_CONSOLE, PortMapper.DEFAULT_CONSOLE_PORT);
String host = ctx.portMapper().getActualHost(PortMapper.SVC_CONSOLE, "127.0.0.1");
ctx.portMapper().register(appName, host, port);
}
use of net.i2p.util.SecureDirectory in project i2p.i2p by i2p.
the class WebAppStarter method addWebApp.
/**
* add but don't start
* This is used only by RouterConsoleRunner, which adds all the webapps first
* and then starts all at once.
*/
static WebAppContext addWebApp(RouterContext ctx, ContextHandlerCollection server, String appName, String warPath, File tmpdir) throws IOException {
// the first one, so we remove any previous one here
try {
stopWebApp(ctx, appName);
} catch (Throwable t) {
}
// To avoid ZipErrors from JarURLConnetion caching,
// (used by Jetty JarResource and JarFileResource)
// copy the war to a new directory if it is newer than the one we loaded originally.
// Yes, URLConnection has a setDefaultUseCaches() method, but it's hard to get to
// because it's non-static and the class is abstract, and we don't really want to
// set the default to false for everything.
long newmod = (new File(warPath)).lastModified();
if (newmod <= 0)
throw new IOException("Web app " + warPath + " does not exist");
Long oldmod = warModTimes.get(warPath);
if (oldmod == null) {
warModTimes.put(warPath, Long.valueOf(newmod));
} else if (oldmod.longValue() < newmod) {
// copy war to temporary directory
File warTmpDir = new SecureDirectory(ctx.getTempDir(), "war-copy-" + appName + ctx.random().nextInt());
warTmpDir.mkdir();
String tmpPath = (new File(warTmpDir, appName + ".war")).getAbsolutePath();
if (!FileUtil.copy(warPath, tmpPath, true))
throw new IOException("Web app failed copy from " + warPath + " to " + tmpPath);
warPath = tmpPath;
}
WebAppContext wac = new WebAppContext(warPath, "/" + appName);
tmpdir.mkdir();
wac.setTempDirectory(tmpdir);
// all the JSPs are precompiled, no need to extract
wac.setExtractWAR(false);
// this does the passwords...
RouterConsoleRunner.initialize(ctx, wac);
setWebAppConfiguration(wac);
server.addHandler(wac);
server.mapContexts();
return wac;
}
use of net.i2p.util.SecureDirectory in project i2p.i2p by i2p.
the class ConfigFamilyHandler method processForm.
@Override
protected void processForm() {
if (_action.equals(_t("Create Family"))) {
String family = getJettyString("family");
String old = _context.getProperty(FamilyKeyCrypto.PROP_FAMILY_NAME);
if (family == null || family.trim().length() <= 0) {
addFormError(_t("You must enter a family name"));
} else if (old != null) {
addFormError("Family already configured: " + family);
} else if (family.contains("/") || family.contains("\\")) {
addFormError("Bad characters in Family: " + family);
} else if (_context.router().saveConfig(FamilyKeyCrypto.PROP_FAMILY_NAME, family.trim())) {
addFormNotice(_t("Configuration saved successfully."));
addFormError(_t("Restart required to take effect"));
} else {
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
}
} else if (_action.equals(_t("Join Family"))) {
InputStream in = _requestWrapper.getInputStream("file");
try {
// non-null but zero bytes if no file entered, don't know why
if (in == null || in.available() <= 0) {
addFormError(_t("You must enter a file"));
return;
}
// load data
PrivateKey pk = CertUtil.loadPrivateKey(in);
List<X509Certificate> certs = CertUtil.loadCerts(in);
String family = CertUtil.getSubjectValue(certs.get(0), "CN");
if (family == null) {
addFormError("Bad certificate - No Subject CN");
}
if (family.endsWith(FamilyKeyCrypto.CN_SUFFIX) && family.length() > FamilyKeyCrypto.CN_SUFFIX.length())
family = family.substring(0, family.length() - FamilyKeyCrypto.CN_SUFFIX.length());
// store to keystore
File ks = new SecureDirectory(_context.getConfigDir(), "keystore");
if (!ks.exists())
ks.mkdirs();
ks = new File(ks, FamilyKeyCrypto.KEYSTORE_PREFIX + family + FamilyKeyCrypto.KEYSTORE_SUFFIX);
String keypw = KeyStoreUtil.randomString();
KeyStoreUtil.storePrivateKey(ks, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, family, keypw, pk, certs);
// store certificate
File cf = new SecureDirectory(_context.getConfigDir(), "certificates");
if (!cf.exists())
cf.mkdirs();
cf = new SecureDirectory(cf, "family");
if (!ks.exists())
ks.mkdirs();
cf = new File(cf, family + FamilyKeyCrypto.CERT_SUFFIX);
// ignore failure
KeyStoreUtil.exportCert(ks, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, family, cf);
// save config
Map<String, String> changes = new HashMap<String, String>();
changes.put(FamilyKeyCrypto.PROP_FAMILY_NAME, family);
changes.put(FamilyKeyCrypto.PROP_KEY_PASSWORD, keypw);
changes.put(FamilyKeyCrypto.PROP_KEYSTORE_PASSWORD, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD);
if (_context.router().saveConfig(changes, null)) {
addFormNotice("Family key configured for router family: " + family);
addFormError(_t("Restart required to take effect"));
} else {
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
}
} catch (GeneralSecurityException gse) {
addFormError(_t("Load from file failed") + " - " + gse);
} catch (IOException ioe) {
addFormError(_t("Load from file failed") + " - " + ioe);
} finally {
// it's really a ByteArrayInputStream but we'll play along...
try {
in.close();
} catch (IOException ioe) {
}
}
} else if (_action.equals(_t("Leave Family"))) {
List<String> removes = new ArrayList<String>();
removes.add(FamilyKeyCrypto.PROP_FAMILY_NAME);
removes.add(FamilyKeyCrypto.PROP_KEY_PASSWORD);
removes.add(FamilyKeyCrypto.PROP_KEYSTORE_PASSWORD);
if (_context.router().saveConfig(null, removes)) {
addFormNotice(_t("Configuration saved successfully."));
addFormError(_t("Restart required to take effect"));
} else {
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
}
}
// addFormError(_t("Unsupported") + ' ' + _action + '.');
}
use of net.i2p.util.SecureDirectory in project i2p.i2p by i2p.
the class PluginUpdateRunner method processFinal.
/**
* @param pubkey null OK for su3
* @since 0.9.15
*/
private void processFinal(File to, File appDir, String url, Properties props, String sudVersion, String pubkey, String signer) {
boolean update = false;
String appName = props.getProperty("name");
String version = props.getProperty("version");
if (appName == null || version == null || appName.length() <= 0 || version.length() <= 0 || appName.indexOf('<') >= 0 || appName.indexOf('>') >= 0 || version.indexOf('<') >= 0 || version.indexOf('>') >= 0 || appName.startsWith(".") || appName.indexOf('/') >= 0 || appName.indexOf('\\') >= 0) {
to.delete();
statusDone("<b>" + _t("Plugin from {0} has invalid name or version", url) + "</b>");
return;
}
if (!version.equals(sudVersion)) {
to.delete();
statusDone("<b>" + _t("Plugin {0} has mismatched versions", appName) + "</b>");
return;
}
// set so notifyComplete() will work
_appName = appName;
_newVersion = version;
String minVersion = PluginStarter.stripHTML(props, "min-i2p-version");
if (minVersion != null && VersionComparator.comp(CoreVersion.VERSION, minVersion) < 0) {
to.delete();
statusDone("<b>" + _t("This plugin requires I2P version {0} or higher", minVersion) + "</b>");
return;
}
minVersion = PluginStarter.stripHTML(props, "min-java-version");
if (minVersion != null && VersionComparator.comp(System.getProperty("java.version"), minVersion) < 0) {
to.delete();
statusDone("<b>" + _t("This plugin requires Java version {0} or higher", minVersion) + "</b>");
return;
}
boolean wasRunning = false;
File destDir = new SecureDirectory(appDir, appName);
if (destDir.exists()) {
if (Boolean.valueOf(props.getProperty("install-only")).booleanValue()) {
to.delete();
statusDone("<b>" + _t("Downloaded plugin is for new installs only, but the plugin is already installed", url) + "</b>");
return;
}
// compare previous version
File oldPropFile = new File(destDir, "plugin.config");
Properties oldProps = new OrderedProperties();
try {
DataHelper.loadProps(oldProps, oldPropFile);
} catch (IOException ioe) {
to.delete();
statusDone("<b>" + _t("Installed plugin does not contain the required configuration file", url) + "</b>");
return;
}
String oldPubkey = oldProps.getProperty("key");
String oldKeyName = oldProps.getProperty("signer");
String oldAppName = oldProps.getProperty("name");
if ((pubkey != null && !pubkey.equals(oldPubkey)) || (!signer.equals(oldKeyName)) || (!appName.equals(oldAppName))) {
to.delete();
statusDone("<b>" + _t("Signature of downloaded plugin does not match installed plugin") + "</b>");
return;
}
String oldVersion = oldProps.getProperty("version");
if (oldVersion == null || VersionComparator.comp(oldVersion, version) >= 0) {
to.delete();
statusDone("<b>" + _t("Downloaded plugin version {0} is not newer than installed plugin", version) + "</b>");
return;
}
minVersion = PluginStarter.stripHTML(props, "min-installed-version");
if (minVersion != null && VersionComparator.comp(minVersion, oldVersion) > 0) {
to.delete();
statusDone("<b>" + _t("Plugin update requires installed plugin version {0} or higher", minVersion) + "</b>");
return;
}
String maxVersion = PluginStarter.stripHTML(props, "max-installed-version");
if (maxVersion != null && VersionComparator.comp(maxVersion, oldVersion) < 0) {
to.delete();
statusDone("<b>" + _t("Plugin update requires installed plugin version {0} or lower", maxVersion) + "</b>");
return;
}
oldVersion = RouterConsoleRunner.jettyVersion();
minVersion = PluginStarter.stripHTML(props, "min-jetty-version");
if (minVersion != null && VersionComparator.comp(minVersion, oldVersion) > 0) {
to.delete();
statusDone("<b>" + _t("Plugin requires Jetty version {0} or higher", minVersion) + "</b>");
return;
}
String blacklistVersion = PluginStarter.jetty9Blacklist.get(appName);
if (blacklistVersion != null && VersionComparator.comp(version, blacklistVersion) <= 0) {
to.delete();
statusDone("<b>" + _t("Plugin requires Jetty version {0} or lower", "8.9999") + "</b>");
return;
}
maxVersion = PluginStarter.stripHTML(props, "max-jetty-version");
if (maxVersion != null && VersionComparator.comp(maxVersion, oldVersion) < 0) {
to.delete();
statusDone("<b>" + _t("Plugin requires Jetty version {0} or lower", maxVersion) + "</b>");
return;
}
// do we defer extraction and installation?
if (Boolean.valueOf(props.getProperty("router-restart-required")).booleanValue()) {
// Yup!
try {
if (!FileUtil.copy(to, (new SecureFile(new SecureFile(appDir.getCanonicalPath() + "/" + appName + "/" + ZIP).getCanonicalPath())), true, true)) {
to.delete();
statusDone("<b>" + _t("Cannot copy plugin to directory {0}", destDir.getAbsolutePath()) + "</b>");
return;
}
} catch (Throwable t) {
to.delete();
_log.error("Error copying plugin {0}", t);
return;
}
// we don't need the original file anymore.
to.delete();
statusDone("<b>" + _t("Plugin will be installed on next restart.") + ' ' + appName + ' ' + version + "</b>");
return;
}
if (PluginStarter.isPluginRunning(appName, _context)) {
wasRunning = true;
try {
if (!PluginStarter.stopPlugin(_context, appName)) {
// failed, ignore
}
} catch (Throwable e) {
// no updateStatus() for this one
_log.error("Error stopping plugin " + appName, e);
}
}
update = true;
} else {
if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
to.delete();
statusDone("<b>" + _t("Plugin is for upgrades only, but the plugin is not installed") + ". " + appName + ' ' + version + "</b>");
return;
}
if (!destDir.mkdir()) {
to.delete();
statusDone("<b>" + _t("Cannot create plugin directory {0}", destDir.getAbsolutePath()) + "</b>");
return;
}
}
// Finally, extract the zip to the plugin directory
if (!FileUtil.extractZip(to, destDir, Log.WARN)) {
to.delete();
statusDone("<b>" + _t("Failed to install plugin in {0}", destDir.getAbsolutePath()) + "</b>");
return;
}
_updated = true;
to.delete();
// install != update. Changing the user's settings like this is probabbly a bad idea.
if (Boolean.valueOf(props.getProperty("dont-start-at-install")).booleanValue()) {
statusDone("<b>" + _t("Plugin {0} installed", appName + ' ' + version) + "</b>");
if (!update) {
Properties pluginProps = PluginStarter.pluginProperties();
pluginProps.setProperty(PluginStarter.PREFIX + appName + PluginStarter.ENABLED, "false");
PluginStarter.storePluginProperties(pluginProps);
}
} else if (wasRunning || PluginStarter.isPluginEnabled(appName)) {
// start everything unless it was disabled and not running before
try {
if (PluginStarter.startPlugin(_context, appName)) {
String linkName = PluginStarter.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(_context));
if (linkName == null)
linkName = PluginStarter.stripHTML(props, "consoleLinkName");
String linkURL = PluginStarter.stripHTML(props, "consoleLinkURL");
String link;
if (linkName != null && linkURL != null)
link = "<a target=\"_blank\" href=\"" + linkURL + "\"/>" + linkName + ' ' + version + "</a>";
else
link = appName + ' ' + version;
statusDone("<b>" + _t("Plugin {0} installed and started", link) + "</b>");
} else
statusDone("<b>" + _t("Plugin {0} installed but failed to start, check logs", appName + ' ' + version) + "</b>");
} catch (Throwable e) {
statusDone("<b>" + _t("Plugin {0} installed but failed to start", appName + ' ' + version) + ": " + e + "</b>");
_log.error("Error starting plugin " + appName + ' ' + version, e);
}
} else {
statusDone("<b>" + _t("Plugin {0} installed", appName + ' ' + version) + "</b>");
}
}
use of net.i2p.util.SecureDirectory in project i2p.i2p by i2p.
the class PersistNews method store.
/**
* Store each entry.
* Old entries are always overwritten, as they may change even without the updated date changing.
*
* @param entries each one should be "entry" at the root
* @return success
*/
public static boolean store(I2PAppContext ctx, List<Node> entries) {
Log log = ctx.logManager().getLog(PersistNews.class);
File dir = new SecureDirectory(ctx.getConfigDir(), DIR);
if (!dir.exists())
dir.mkdirs();
StringBuilder buf = new StringBuilder();
boolean rv = true;
for (Node entry : entries) {
Node nid = entry.getNode("id");
if (nid == null) {
if (log.shouldWarn())
log.warn("entry without UUID");
continue;
}
String id = nid.getValue();
if (id == null) {
if (log.shouldWarn())
log.warn("entry without UUID");
continue;
}
String name = idToName(ctx, id);
File file = new File(dir, name);
Writer out = null;
try {
out = new OutputStreamWriter(new GZIPOutputStream(new SecureFileOutputStream(file)));
out.write(XML_START);
XMLParser.toString(buf, entry);
out.write(buf.toString());
buf.setLength(0);
} catch (IOException ioe) {
if (log.shouldWarn())
log.warn("failed store to " + file, ioe);
rv = false;
} finally {
if (out != null)
try {
out.close();
} catch (IOException ioe) {
}
}
}
return rv;
}
Aggregations