forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p.zzz.update' (head 267311f29e501fcc8b3d674a93e78b5520ac985e)
to branch 'i2p.i2p' (head edeca2ab47e734c2314ff394609292d8bd3d5293)
This commit is contained in:
@ -18,15 +18,15 @@ import java.util.TreeMap;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.Shitlist;
|
||||
import net.i2p.router.Banlist;
|
||||
|
||||
/**
|
||||
* Moved from Shitlist.java
|
||||
* Moved from Banlist.java
|
||||
*/
|
||||
public class ShitlistRenderer {
|
||||
public class BanlistRenderer {
|
||||
private final RouterContext _context;
|
||||
|
||||
public ShitlistRenderer(RouterContext context) {
|
||||
public BanlistRenderer(RouterContext context) {
|
||||
_context = context;
|
||||
}
|
||||
|
||||
@ -40,9 +40,9 @@ public class ShitlistRenderer {
|
||||
StringBuilder buf = new StringBuilder(1024);
|
||||
// move to the jsp
|
||||
//buf.append("<h2>Banned Peers</h2>");
|
||||
Map<Hash, Shitlist.Entry> entries = new TreeMap(new HashComparator());
|
||||
Map<Hash, Banlist.Entry> entries = new TreeMap(new HashComparator());
|
||||
|
||||
entries.putAll(_context.shitlist().getEntries());
|
||||
entries.putAll(_context.banlist().getEntries());
|
||||
if (entries.isEmpty()) {
|
||||
buf.append("<i>").append(_("none")).append("</i>");
|
||||
out.write(buf.toString());
|
||||
@ -51,9 +51,9 @@ public class ShitlistRenderer {
|
||||
|
||||
buf.append("<ul>");
|
||||
|
||||
for (Map.Entry<Hash, Shitlist.Entry> e : entries.entrySet()) {
|
||||
for (Map.Entry<Hash, Banlist.Entry> e : entries.entrySet()) {
|
||||
Hash key = e.getKey();
|
||||
Shitlist.Entry entry = e.getValue();
|
||||
Banlist.Entry entry = e.getValue();
|
||||
long expires = entry.expireOn-_context.clock().now();
|
||||
if (expires <= 0)
|
||||
continue;
|
@ -23,7 +23,6 @@ import org.mortbay.jetty.handler.ContextHandlerCollection;
|
||||
* Saves changes to clients.config or webapps.config
|
||||
*/
|
||||
public class ConfigClientsHandler extends FormHandler {
|
||||
private Map _settings;
|
||||
|
||||
@Override
|
||||
protected void processForm() {
|
||||
@ -171,8 +170,6 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
|
||||
}
|
||||
|
||||
public void setSettings(Map settings) { _settings = new HashMap(settings); }
|
||||
|
||||
private void saveClientChanges() {
|
||||
List<ClientAppConfig> clients = ClientAppConfig.getClientApps(_context);
|
||||
for (int cur = 0; cur < clients.size(); cur++) {
|
||||
@ -216,15 +213,8 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
}
|
||||
|
||||
ClientAppConfig.writeClientAppConfig(_context, clients);
|
||||
addFormNotice(_("Client configuration saved successfully - restart required to take effect."));
|
||||
}
|
||||
|
||||
/** curses Jetty for returning arrays */
|
||||
private String getJettyString(String key) {
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0].trim();
|
||||
addFormNotice(_("Client configuration saved successfully"));
|
||||
addFormNotice(_("Restart required to take effect"));
|
||||
}
|
||||
|
||||
// STUB for stopClient, not completed yet.
|
||||
@ -248,7 +238,7 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
return;
|
||||
}
|
||||
ClientAppConfig ca = clients.get(i);
|
||||
LoadClientAppsJob.runClient(ca.className, ca.clientName, LoadClientAppsJob.parseArgs(ca.args), _log);
|
||||
LoadClientAppsJob.runClient(ca.className, ca.clientName, LoadClientAppsJob.parseArgs(ca.args), _context, _log);
|
||||
addFormNotice(_("Client") + ' ' + _(ca.clientName) + ' ' + _("started") + '.');
|
||||
}
|
||||
|
||||
@ -264,7 +254,7 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
}
|
||||
|
||||
private void saveWebAppChanges() {
|
||||
Properties props = RouterConsoleRunner.webAppProperties();
|
||||
Properties props = RouterConsoleRunner.webAppProperties(_context);
|
||||
Set keys = props.keySet();
|
||||
for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
@ -275,7 +265,7 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
if (! RouterConsoleRunner.ROUTERCONSOLE.equals(app))
|
||||
props.setProperty(name, "" + (val != null));
|
||||
}
|
||||
RouterConsoleRunner.storeWebAppProperties(props);
|
||||
RouterConsoleRunner.storeWebAppProperties(_context, props);
|
||||
addFormNotice(_("WebApp configuration saved."));
|
||||
}
|
||||
|
||||
@ -416,11 +406,12 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
if (intfc != null)
|
||||
changes.put(ClientManagerFacadeImpl.PROP_CLIENT_HOST, intfc);
|
||||
String user = getJettyString("user");
|
||||
if (user != null)
|
||||
changes.put(ConfigClientsHelper.PROP_USER, user);
|
||||
String pw = getJettyString("pw");
|
||||
if (pw != null)
|
||||
changes.put(ConfigClientsHelper.PROP_PW, pw);
|
||||
if (user != null && pw != null && user.length() > 0 && pw.length() > 0) {
|
||||
ConsolePasswordManager mgr = new ConsolePasswordManager(_context);
|
||||
mgr.saveHash(ConfigClientsHelper.PROP_AUTH, user, pw);
|
||||
addFormNotice(_("Added user {0}", user));
|
||||
}
|
||||
String mode = getJettyString("mode");
|
||||
boolean disabled = "0".equals(mode);
|
||||
boolean ssl = "2".equals(mode);
|
||||
@ -433,9 +424,10 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
boolean all = "0.0.0.0".equals(intfc) || "0:0:0:0:0:0:0:0".equals(intfc) ||
|
||||
"::".equals(intfc);
|
||||
changes.put(ConfigClientsHelper.BIND_ALL_INTERFACES, Boolean.toString(all));
|
||||
if (_context.router().saveConfig(changes, null))
|
||||
addFormNotice(_("Interface configuration saved successfully - restart required to take effect."));
|
||||
else
|
||||
if (_context.router().saveConfig(changes, null)) {
|
||||
addFormNotice(_("Interface configuration saved"));
|
||||
addFormNotice(_("Restart required to take effect"));
|
||||
} else
|
||||
addFormError(_("Error saving the configuration (applied but not saved) - please see the error logs"));
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,6 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
public static final String PROP_ENABLE_SSL = "i2cp.SSL";
|
||||
/** from ClientMessageEventListener */
|
||||
public static final String PROP_AUTH = "i2cp.auth";
|
||||
public static final String PROP_USER = "i2cp.username";
|
||||
public static final String PROP_PW = "i2cp.password";
|
||||
|
||||
public ConfigClientsHelper() {}
|
||||
|
||||
@ -35,16 +33,6 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
Integer.toString(ClientManagerFacadeImpl.DEFAULT_PORT));
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String getUser() {
|
||||
return _context.getProperty(PROP_USER, "");
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String getPw() {
|
||||
return _context.getProperty(PROP_PW, "");
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String i2cpModeChecked(int mode) {
|
||||
boolean disabled = _context.getBooleanProperty(PROP_DISABLE_EXTERNAL);
|
||||
@ -128,7 +116,7 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
StringBuilder buf = new StringBuilder(1024);
|
||||
buf.append("<table>\n");
|
||||
buf.append("<tr><th align=\"right\">" + _("WebApp") + "</th><th>" + _("Run at Startup?") + "</th><th>" + _("Control") + "</th><th align=\"left\">" + _("Description") + "</th></tr>\n");
|
||||
Properties props = RouterConsoleRunner.webAppProperties();
|
||||
Properties props = RouterConsoleRunner.webAppProperties(_context);
|
||||
Set<String> keys = new TreeSet(props.keySet());
|
||||
for (Iterator<String> iter = keys.iterator(); iter.hasNext(); ) {
|
||||
String name = iter.next();
|
||||
|
@ -1,11 +1,9 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
@ -16,8 +14,6 @@ import net.i2p.data.DataHelper;
|
||||
*/
|
||||
public class ConfigHomeHandler extends FormHandler {
|
||||
|
||||
private Map _settings;
|
||||
|
||||
@Override
|
||||
protected void processForm() {
|
||||
if (_action == null) return;
|
||||
@ -106,14 +102,4 @@ public class ConfigHomeHandler extends FormHandler {
|
||||
addFormError(_("Unsupported"));
|
||||
}
|
||||
}
|
||||
|
||||
public void setSettings(Map settings) { _settings = new HashMap(settings); }
|
||||
|
||||
/** curses Jetty for returning arrays */
|
||||
private String getJettyString(String key) {
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0].trim();
|
||||
}
|
||||
}
|
||||
|
@ -280,9 +280,10 @@ public class ConfigNetHandler extends FormHandler {
|
||||
_upnp) {
|
||||
// This is minor, don't set restartRequired
|
||||
if (_upnp)
|
||||
addFormNotice(_("Enabling UPnP, restart required to take effect"));
|
||||
addFormNotice(_("Enabling UPnP"));
|
||||
else
|
||||
addFormNotice(_("Disabling UPnP, restart required to take effect"));
|
||||
addFormNotice(_("Disabling UPnP"));
|
||||
addFormNotice(_("Restart required to take effect"));
|
||||
}
|
||||
changes.put(TransportManager.PROP_ENABLE_UPNP, "" + _upnp);
|
||||
|
||||
|
@ -20,7 +20,7 @@ public class ConfigPeerHandler extends FormHandler {
|
||||
} else if (_action.equals(_("Ban peer until restart"))) {
|
||||
Hash h = getHash();
|
||||
if (h != null) {
|
||||
_context.shitlist().shitlistRouterForever(h, _("Manually banned via {0}"), "<a href=\"configpeer\">configpeer</a>");
|
||||
_context.banlist().banlistRouterForever(h, _("Manually banned via {0}"), "<a href=\"configpeer\">configpeer</a>");
|
||||
addFormNotice(_("Peer") + " " + _peer + " " + _("banned until restart") );
|
||||
return;
|
||||
}
|
||||
@ -28,8 +28,8 @@ public class ConfigPeerHandler extends FormHandler {
|
||||
} else if (_action.equals(_("Unban peer"))) {
|
||||
Hash h = getHash();
|
||||
if (h != null) {
|
||||
if (_context.shitlist().isShitlisted(h)) {
|
||||
_context.shitlist().unshitlistRouter(h);
|
||||
if (_context.banlist().isBanlisted(h)) {
|
||||
_context.banlist().unbanlistRouter(h);
|
||||
addFormNotice(_("Peer") + " " + _peer + " " + _("unbanned") );
|
||||
} else
|
||||
addFormNotice(_("Peer") + " " + _peer + " " + _("is not currently banned") );
|
||||
|
@ -11,7 +11,6 @@ import net.i2p.router.networkdb.reseed.Reseeder;
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public class ConfigReseedHandler extends FormHandler {
|
||||
private Map _settings;
|
||||
private final Map<String, String> changes = new HashMap();
|
||||
private final List<String> removes = new ArrayList();
|
||||
|
||||
@ -34,16 +33,6 @@ public class ConfigReseedHandler extends FormHandler {
|
||||
}
|
||||
addFormError(_("Unsupported") + ' ' + _action + '.');
|
||||
}
|
||||
|
||||
public void setSettings(Map settings) { _settings = new HashMap(settings); }
|
||||
|
||||
/** curses Jetty for returning arrays */
|
||||
private String getJettyString(String key) {
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0].trim();
|
||||
}
|
||||
|
||||
/** @since 0.8.9 */
|
||||
private void saveString(String config, String param) {
|
||||
|
@ -8,6 +8,7 @@ import net.i2p.apps.systray.UrlLauncher;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.startup.ClientAppConfig;
|
||||
import net.i2p.util.PortMapper;
|
||||
import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
@ -257,7 +258,9 @@ public class ConfigServiceHandler extends FormHandler {
|
||||
}
|
||||
// releases <= 0.6.5 deleted the entry completely
|
||||
if (shouldLaunchBrowser && !found) {
|
||||
ClientAppConfig ca = new ClientAppConfig(UrlLauncher.class.getName(), "consoleBrowser", "http://127.0.0.1:7657", 5, false);
|
||||
int port = _context.portMapper().getPort(PortMapper.SVC_CONSOLE, RouterConsoleRunner.DEFAULT_LISTEN_PORT);
|
||||
ClientAppConfig ca = new ClientAppConfig(UrlLauncher.class.getName(), "consoleBrowser",
|
||||
"http://127.0.0.1:" + port + '/', 5, false);
|
||||
clients.add(ca);
|
||||
}
|
||||
ClientAppConfig.writeClientAppConfig(_context, clients);
|
||||
|
@ -116,9 +116,10 @@ public class ConfigStatsHandler extends FormHandler {
|
||||
addFormNotice(_("Stat filter and location updated successfully to") + ": " + stats.toString());
|
||||
if (fullChanged) {
|
||||
if (_isFull)
|
||||
addFormNotice(_("Full statistics enabled - restart required to take effect"));
|
||||
addFormNotice(_("Full statistics enabled"));
|
||||
else
|
||||
addFormNotice(_("Full statistics disabled - restart required to take effect"));
|
||||
addFormNotice(_("Full statistics disabled"));
|
||||
addFormNotice(_("Restart required to take effect"));
|
||||
}
|
||||
if (graphsChanged)
|
||||
addFormNotice(_("Graph list updated, may take up to 60s to be reflected here and on the <a href=\"graphs.jsp\">Graphs Page</a>"));
|
||||
|
@ -1,7 +1,6 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@ -16,8 +15,6 @@ import net.i2p.data.DataHelper;
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public class ConfigSummaryHandler extends FormHandler {
|
||||
|
||||
private Map _settings;
|
||||
|
||||
@Override
|
||||
protected void processForm() {
|
||||
@ -144,16 +141,6 @@ public class ConfigSummaryHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void setSettings(Map settings) { _settings = new HashMap(settings); }
|
||||
|
||||
/** curses Jetty for returning arrays */
|
||||
private String getJettyString(String key) {
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0].trim();
|
||||
}
|
||||
|
||||
public void setMovingAction() {
|
||||
for (Object o : _settings.keySet()) {
|
||||
if (!(o instanceof String))
|
||||
|
@ -13,8 +13,13 @@ public class ConfigUIHandler extends FormHandler {
|
||||
|
||||
@Override
|
||||
protected void processForm() {
|
||||
if (_shouldSave)
|
||||
if (_shouldSave) {
|
||||
saveChanges();
|
||||
} else if (_action.equals(_("Delete selected"))) {
|
||||
delUser();
|
||||
} else if (_action.equals(_("Add user"))) {
|
||||
addUser();
|
||||
}
|
||||
}
|
||||
|
||||
public void setShouldsave(String moo) { _shouldSave = true; }
|
||||
@ -51,4 +56,48 @@ public class ConfigUIHandler extends FormHandler {
|
||||
addFormError(_("Error saving the configuration (applied but not saved) - please see the error logs."));
|
||||
}
|
||||
}
|
||||
|
||||
private void addUser() {
|
||||
String name = getJettyString("name");
|
||||
if (name == null || name.length() <= 0) {
|
||||
addFormError(_("No user name entered"));
|
||||
return;
|
||||
}
|
||||
String pw = getJettyString("pw");
|
||||
if (pw == null || pw.length() <= 0) {
|
||||
addFormError(_("No password entered"));
|
||||
return;
|
||||
}
|
||||
ConsolePasswordManager mgr = new ConsolePasswordManager(_context);
|
||||
// rfc 2617
|
||||
if (mgr.saveMD5(RouterConsoleRunner.PROP_CONSOLE_PW, RouterConsoleRunner.JETTY_REALM, name, pw)) {
|
||||
if (!_context.getBooleanProperty(RouterConsoleRunner.PROP_PW_ENABLE))
|
||||
_context.router().saveConfig(RouterConsoleRunner.PROP_PW_ENABLE, "true");
|
||||
addFormNotice(_("Added user {0}", name));
|
||||
addFormNotice(_("Restart required to take effect"));
|
||||
} else {
|
||||
addFormError(_("Error saving the configuration (applied but not saved) - please see the error logs."));
|
||||
}
|
||||
}
|
||||
|
||||
private void delUser() {
|
||||
ConsolePasswordManager mgr = new ConsolePasswordManager(_context);
|
||||
boolean success = false;
|
||||
for (Object o : _settings.keySet()) {
|
||||
if (!(o instanceof String))
|
||||
continue;
|
||||
String k = (String) o;
|
||||
if (!k.startsWith("delete_"))
|
||||
continue;
|
||||
k = k.substring(7);
|
||||
if (mgr.remove(RouterConsoleRunner.PROP_CONSOLE_PW, k)) {
|
||||
addFormNotice(_("Removed user {0}", k));
|
||||
success = true;
|
||||
} else {
|
||||
addFormError(_("Error saving the configuration (applied but not saved) - please see the error logs."));
|
||||
}
|
||||
}
|
||||
if (success)
|
||||
addFormNotice(_("Restart required to take effect"));
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,9 @@ package net.i2p.router.web;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class ConfigUIHelper extends HelperBase {
|
||||
|
||||
@ -87,4 +88,38 @@ public class ConfigUIHelper extends HelperBase {
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public String getPasswordForm() {
|
||||
StringBuilder buf = new StringBuilder(512);
|
||||
ConsolePasswordManager mgr = new ConsolePasswordManager(_context);
|
||||
Map<String, String> userpw = mgr.getMD5(RouterConsoleRunner.PROP_CONSOLE_PW);
|
||||
buf.append("<table>");
|
||||
if (userpw.isEmpty()) {
|
||||
buf.append("<tr><td colspan=\"3\">");
|
||||
buf.append(_("Add a user and password to enable."));
|
||||
buf.append("</td></tr>");
|
||||
} else {
|
||||
buf.append("<tr><th>")
|
||||
.append(_("Remove"))
|
||||
.append("</th><th>")
|
||||
.append(_("User Name"))
|
||||
.append("</th><th> </th></tr>\n");
|
||||
for (String name : userpw.keySet()) {
|
||||
buf.append("<tr><td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"delete_")
|
||||
.append(name)
|
||||
.append("\"></td><td colspan=\"2\">")
|
||||
.append(name)
|
||||
.append("</td></tr>\n");
|
||||
}
|
||||
}
|
||||
buf.append("<tr><td align=\"center\"><b>")
|
||||
.append(_("Add")).append(":</b>" +
|
||||
"</td><td align=\"left\"><input type=\"text\" name=\"name\">" +
|
||||
"</td><td align=\"left\"><b>");
|
||||
buf.append(_("Password")).append(":</b> " +
|
||||
"<input type=\"password\" size=\"40\" name=\"pw\"></td></tr>" +
|
||||
"</table>\n");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,213 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.util.RouterPasswordManager;
|
||||
|
||||
//import org.mortbay.jetty.security.UnixCrypt;
|
||||
|
||||
/**
|
||||
* Manage both plaintext and salted/hashed password storage in
|
||||
* router.config.
|
||||
*
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public class ConsolePasswordManager extends RouterPasswordManager {
|
||||
|
||||
private static final String PROP_MIGRATED = "routerconsole.passwordManager.migrated";
|
||||
// migrate these to hash
|
||||
private static final String PROP_CONSOLE_OLD = "consolePassword";
|
||||
private static final String CONSOLE_USER = "admin";
|
||||
|
||||
public ConsolePasswordManager(RouterContext ctx) {
|
||||
super(ctx);
|
||||
migrateConsole();
|
||||
}
|
||||
|
||||
/**
|
||||
* The username is the salt
|
||||
*
|
||||
* @param realm e.g. i2cp, routerconsole, etc.
|
||||
* @param user null or "" for no user, already trimmed
|
||||
* @param pw plain text, already trimmed
|
||||
* @return if pw verified
|
||||
*/
|
||||
/****
|
||||
public boolean checkCrypt(String realm, String user, String pw) {
|
||||
String pfx = realm;
|
||||
if (user != null && user.length() > 0)
|
||||
pfx += '.' + user;
|
||||
String cr = _context.getProperty(pfx + PROP_CRYPT);
|
||||
if (cr == null)
|
||||
return false;
|
||||
return cr.equals(UnixCrypt.crypt(pw, cr));
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Straight MD5. Compatible with Jetty.
|
||||
*
|
||||
* @param realm e.g. i2cp, routerconsole, etc.
|
||||
* @param user null or "" for no user, already trimmed
|
||||
* @param pw plain text, already trimmed
|
||||
* @return if pw verified
|
||||
*/
|
||||
public boolean checkMD5(String realm, String subrealm, String user, String pw) {
|
||||
String pfx = realm;
|
||||
if (user != null && user.length() > 0)
|
||||
pfx += '.' + user;
|
||||
String hex = _context.getProperty(pfx + PROP_MD5);
|
||||
if (hex == null)
|
||||
return false;
|
||||
return hex.equals(md5Hex(subrealm, user, pw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all MD5 usernames and passwords. Compatible with Jetty.
|
||||
* Any "null" user is NOT included..
|
||||
*
|
||||
* @param realm e.g. i2cp, routerconsole, etc.
|
||||
* @return Map of usernames to passwords (hex with leading zeros, 32 characters)
|
||||
*/
|
||||
public Map<String, String> getMD5(String realm) {
|
||||
String pfx = realm + '.';
|
||||
Map<String, String> rv = new HashMap(4);
|
||||
for (Map.Entry<String, String> e : _context.router().getConfigMap().entrySet()) {
|
||||
String prop = e.getKey();
|
||||
if (prop.startsWith(pfx) && prop.endsWith(PROP_MD5)) {
|
||||
String user = prop.substring(0, prop.length() - PROP_MD5.length()).substring(pfx.length());
|
||||
String hex = e.getValue();
|
||||
if (user.length() > 0 && hex.length() == 32)
|
||||
rv.put(user, hex);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate from plaintext to MD5 hash
|
||||
* Ref: RFC 2617
|
||||
*
|
||||
* @return success or nothing to migrate
|
||||
*/
|
||||
private boolean migrateConsole() {
|
||||
synchronized(ConsolePasswordManager.class) {
|
||||
if (_context.getBooleanProperty(PROP_MIGRATED))
|
||||
return true;
|
||||
// consolePassword
|
||||
String pw = _context.getProperty(PROP_CONSOLE_OLD);
|
||||
if (pw != null) {
|
||||
Map toAdd = new HashMap(2);
|
||||
if (pw.length() > 0) {
|
||||
saveMD5(RouterConsoleRunner.PROP_CONSOLE_PW, RouterConsoleRunner.JETTY_REALM,
|
||||
CONSOLE_USER, pw);
|
||||
toAdd.put(RouterConsoleRunner.PROP_PW_ENABLE, "true");
|
||||
}
|
||||
toAdd.put(PROP_MIGRATED, "true");
|
||||
List toDel = Collections.singletonList(PROP_CONSOLE_OLD);
|
||||
return _context.router().saveConfig(toAdd, toDel);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will fail if
|
||||
* user contains '#' or '=' or starts with '!'
|
||||
* The user is the salt.
|
||||
*
|
||||
* @param realm e.g. i2cp, routerconsole, etc.
|
||||
* @param user null or "" for no user, already trimmed
|
||||
* @param pw plain text, already trimmed
|
||||
* @return success
|
||||
*/
|
||||
/****
|
||||
public boolean saveCrypt(String realm, String user, String pw) {
|
||||
String pfx = realm;
|
||||
if (user != null && user.length() > 0)
|
||||
pfx += '.' + user;
|
||||
String salt = user != null ? user : "";
|
||||
String crypt = UnixCrypt.crypt(pw, salt);
|
||||
Map<String, String> toAdd = Collections.singletonMap(pfx + PROP_CRYPT, crypt);
|
||||
List<String> toDel = new ArrayList(4);
|
||||
toDel.add(pfx + PROP_PW);
|
||||
toDel.add(pfx + PROP_B64);
|
||||
toDel.add(pfx + PROP_MD5);
|
||||
toDel.add(pfx + PROP_SHASH);
|
||||
return _context.router().saveConfig(toAdd, toDel);
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Straight MD5, no salt
|
||||
* Compatible with Jetty and RFC 2617.
|
||||
*
|
||||
* @param realm The full realm, e.g. routerconsole.auth.i2prouter, etc.
|
||||
* @param subrealm to be used in creating the checksum
|
||||
* @param user non-null, non-empty, already trimmed
|
||||
* @param pw plain text
|
||||
* @return if pw verified
|
||||
*/
|
||||
public boolean saveMD5(String realm, String subrealm, String user, String pw) {
|
||||
String pfx = realm;
|
||||
if (user != null && user.length() > 0)
|
||||
pfx += '.' + user;
|
||||
String hex = md5Hex(subrealm, user, pw);
|
||||
if (hex == null)
|
||||
return false;
|
||||
Map<String, String> toAdd = Collections.singletonMap(pfx + PROP_MD5, hex);
|
||||
List<String> toDel = new ArrayList(4);
|
||||
toDel.add(pfx + PROP_PW);
|
||||
toDel.add(pfx + PROP_B64);
|
||||
toDel.add(pfx + PROP_CRYPT);
|
||||
toDel.add(pfx + PROP_SHASH);
|
||||
return _context.router().saveConfig(toAdd, toDel);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
RouterContext ctx = (new Router()).getContext();
|
||||
ConsolePasswordManager pm = new ConsolePasswordManager(ctx);
|
||||
if (!pm.migrate())
|
||||
System.out.println("Fail 1");
|
||||
if (!pm.migrateConsole())
|
||||
System.out.println("Fail 1a");
|
||||
|
||||
System.out.println("Test plain");
|
||||
if (!pm.savePlain("type1", "user1", "pw1"))
|
||||
System.out.println("Fail 2");
|
||||
if (!pm.checkPlain("type1", "user1", "pw1"))
|
||||
System.out.println("Fail 3");
|
||||
|
||||
System.out.println("Test B64");
|
||||
if (!pm.saveB64("type2", "user2", "pw2"))
|
||||
System.out.println("Fail 4");
|
||||
if (!pm.checkB64("type2", "user2", "pw2"))
|
||||
System.out.println("Fail 5");
|
||||
|
||||
System.out.println("Test MD5");
|
||||
if (!pm.saveMD5("type3", "realm", "user3", "pw3"))
|
||||
System.out.println("Fail 6");
|
||||
if (!pm.checkMD5("type3", "realm", "user3", "pw3"))
|
||||
System.out.println("Fail 7");
|
||||
|
||||
//System.out.println("Test crypt");
|
||||
//if (!pm.saveCrypt("type4", "user4", "pw4"))
|
||||
// System.out.println("Fail 8");
|
||||
//if (!pm.checkCrypt("type4", "user4", "pw4"))
|
||||
// System.out.println("Fail 9");
|
||||
|
||||
System.out.println("Test hash");
|
||||
if (!pm.saveHash("type5", "user5", "pw5"))
|
||||
System.out.println("Fail 10");
|
||||
if (!pm.checkHash("type5", "user5", "pw5"))
|
||||
System.out.println("Fail 11");
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
@ -18,16 +20,14 @@ import net.i2p.util.Log;
|
||||
public class FormHandler {
|
||||
protected RouterContext _context;
|
||||
protected Log _log;
|
||||
private String _nonce;
|
||||
protected Map _settings;
|
||||
private String _nonce, _nonce1, _nonce2;
|
||||
protected String _action;
|
||||
protected String _method;
|
||||
protected String _passphrase;
|
||||
private final List<String> _errors;
|
||||
private final List<String> _notices;
|
||||
private boolean _processed;
|
||||
private boolean _valid;
|
||||
private static final String NONCE_SUFFIX = ".nonce";
|
||||
private static final String PREV_SUFFIX = "Prev";
|
||||
|
||||
public FormHandler() {
|
||||
_errors = new ArrayList();
|
||||
@ -52,7 +52,28 @@ public class FormHandler {
|
||||
|
||||
public void setNonce(String val) { _nonce = val; }
|
||||
public void setAction(String val) { _action = val; }
|
||||
public void setPassphrase(String val) { _passphrase = val; }
|
||||
|
||||
/**
|
||||
* For many forms, it's easiest just to put all the parameters here.
|
||||
*
|
||||
* @since 0.9.4 consolidated from numerous FormHandlers
|
||||
*/
|
||||
public void setSettings(Map settings) { _settings = new HashMap(settings); }
|
||||
|
||||
/**
|
||||
* setSettings() must have been called previously
|
||||
* Curses Jetty for returning arrays.
|
||||
*
|
||||
* @since 0.9.4 consolidated from numerous FormHandlers
|
||||
*/
|
||||
protected String getJettyString(String key) {
|
||||
if (_settings == null)
|
||||
return null;
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0].trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to prevent changes using GET
|
||||
@ -61,6 +82,15 @@ public class FormHandler {
|
||||
* @since 0.8.2
|
||||
*/
|
||||
public void storeMethod(String val) { _method = val; }
|
||||
|
||||
/**
|
||||
* The old nonces from the session
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public void storeNonces(String n1, String n2) {
|
||||
_nonce1 = n1;
|
||||
_nonce2 = n2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to perform the final processing (in turn, adding formNotice
|
||||
@ -147,35 +177,33 @@ public class FormHandler {
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
if (_nonce == null) {
|
||||
//addFormError("You trying to mess with me? Huh? Are you?");
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
// To prevent actions with GET, jsps must call storeMethod()
|
||||
if (_method != null && !"POST".equals(_method)) {
|
||||
addFormError("Invalid form submission, requires POST not " + _method);
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
// If passwords are turned on, all is assumed good
|
||||
if (_context.getBooleanProperty(RouterConsoleRunner.PROP_PW_ENABLE)) {
|
||||
_valid = true;
|
||||
return;
|
||||
}
|
||||
if (_nonce == null) {
|
||||
//addFormError("You trying to mess with me? Huh? Are you?");
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
String sharedNonce = System.getProperty("router.consoleNonce");
|
||||
if ( (sharedNonce != null) && (sharedNonce.equals(_nonce) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
String nonce = System.getProperty(getClass().getName() + NONCE_SUFFIX);
|
||||
String noncePrev = nonce + PREV_SUFFIX;
|
||||
if ( ( (nonce == null) || (!_nonce.equals(nonce)) ) &&
|
||||
( (noncePrev == null) || (!_nonce.equals(noncePrev)) ) ) {
|
||||
|
||||
String expected = _context.getProperty("consolePassword");
|
||||
if ( (expected != null) && (expected.trim().length() > 0) && (expected.equals(_passphrase)) ) {
|
||||
// ok
|
||||
} else {
|
||||
addFormError(_("Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit."));
|
||||
if (!_nonce.equals(_nonce1) && !_nonce.equals(_nonce2)) {
|
||||
addFormError(_("Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit.")
|
||||
+ ' ' +
|
||||
_("If the problem persists, verify that you have cookies enabled in your browser."));
|
||||
_valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,18 +232,13 @@ public class FormHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new nonce, store old and new in the system properties.
|
||||
* Generate a new nonce.
|
||||
* Only call once per page!
|
||||
* @return a new random long as a String
|
||||
* @since 0.8.5
|
||||
*/
|
||||
public String getNewNonce() {
|
||||
String prop = getClass().getName() + NONCE_SUFFIX;
|
||||
String prev = System.getProperty(prop);
|
||||
if (prev != null)
|
||||
System.setProperty(prop + PREV_SUFFIX, prev);
|
||||
String rv = Long.toString(_context.random().nextLong());
|
||||
System.setProperty(prop, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ public class PluginStarter implements Runnable {
|
||||
// quick check, will throw ClassNotFoundException on error
|
||||
LoadClientAppsJob.testClient(app.className, cl);
|
||||
// run this guy now
|
||||
LoadClientAppsJob.runClient(app.className, app.clientName, argVal, log, pluginThreadGroup, cl);
|
||||
LoadClientAppsJob.runClient(app.className, app.clientName, argVal, ctx, log, pluginThreadGroup, cl);
|
||||
} else {
|
||||
// If there is some delay, there may be a really good reason for it.
|
||||
// Loading a class would be one of them!
|
||||
|
@ -168,7 +168,7 @@ class ProfileOrganizerRenderer {
|
||||
}
|
||||
buf.append("</td><td align=\"right\">").append(num(prof.getIntegrationValue()));
|
||||
buf.append("</td><td align=\"center\">");
|
||||
if (_context.shitlist().isShitlisted(peer)) buf.append(_("Banned"));
|
||||
if (_context.banlist().isBanlisted(peer)) buf.append(_("Banned"));
|
||||
if (prof.getIsFailing()) buf.append(' ').append(_("Failing"));
|
||||
if (_context.commSystem().wasUnreachable(peer)) buf.append(' ').append(_("Unreachable"));
|
||||
Rate failed = prof.getTunnelHistory().getFailedRate().getRate(30*60*1000);
|
||||
|
@ -46,7 +46,7 @@ public class ProfilesHelper extends HelperBase {
|
||||
renderNavBar();
|
||||
} catch (IOException ioe) {}
|
||||
if (_full == 3)
|
||||
getShitlistSummary();
|
||||
getBanlistSummary();
|
||||
else
|
||||
getProfileSummary();
|
||||
return "";
|
||||
@ -64,9 +64,9 @@ public class ProfilesHelper extends HelperBase {
|
||||
}
|
||||
|
||||
/** @return empty string, writes directly to _out */
|
||||
public String getShitlistSummary() {
|
||||
public String getBanlistSummary() {
|
||||
try {
|
||||
ShitlistRenderer rend = new ShitlistRenderer(_context);
|
||||
BanlistRenderer rend = new BanlistRenderer(_context);
|
||||
rend.renderStatusHTML(_out);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
|
@ -23,11 +23,15 @@ import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
import net.i2p.apps.systray.SysTray;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.update.ConsoleUpdateManager;
|
||||
import net.i2p.router.app.RouterApp;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
@ -48,6 +52,7 @@ import org.mortbay.jetty.handler.DefaultHandler;
|
||||
import org.mortbay.jetty.handler.HandlerCollection;
|
||||
import org.mortbay.jetty.handler.RequestLogHandler;
|
||||
import org.mortbay.jetty.nio.SelectChannelConnector;
|
||||
import org.mortbay.jetty.security.Credential.MD5;
|
||||
import org.mortbay.jetty.security.DigestAuthenticator;
|
||||
import org.mortbay.jetty.security.HashUserRealm;
|
||||
import org.mortbay.jetty.security.Constraint;
|
||||
@ -65,7 +70,10 @@ import org.mortbay.thread.concurrent.ThreadPool;
|
||||
/**
|
||||
* Start the router console.
|
||||
*/
|
||||
public class RouterConsoleRunner {
|
||||
public class RouterConsoleRunner implements RouterApp {
|
||||
private final RouterContext _context;
|
||||
private final ClientAppManager _mgr;
|
||||
private volatile ClientAppState _state = UNINITIALIZED;
|
||||
private static Server _server;
|
||||
private String _listenPort;
|
||||
private String _listenHost;
|
||||
@ -74,14 +82,21 @@ public class RouterConsoleRunner {
|
||||
private String _webAppsDir;
|
||||
|
||||
private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config";
|
||||
|
||||
// Jetty Auth
|
||||
private static final DigestAuthenticator authenticator = new DigestAuthenticator();
|
||||
public static final String JETTY_REALM = "i2prouter";
|
||||
private static final String JETTY_ROLE = "routerAdmin";
|
||||
public static final String PROP_CONSOLE_PW = "routerconsole.auth." + JETTY_REALM;
|
||||
public static final String PROP_PW_ENABLE = "routerconsole.auth.enable";
|
||||
|
||||
public static final String ROUTERCONSOLE = "routerconsole";
|
||||
public static final String PREFIX = "webapps.";
|
||||
public static final String ENABLED = ".startOnLoad";
|
||||
private static final String PROP_KEYSTORE_PASSWORD = "routerconsole.keystorePassword";
|
||||
private static final String DEFAULT_KEYSTORE_PASSWORD = "changeit";
|
||||
private static final String PROP_KEY_PASSWORD = "routerconsole.keyPassword";
|
||||
private static final String DEFAULT_LISTEN_PORT = "7657";
|
||||
public static final int DEFAULT_LISTEN_PORT = 7657;
|
||||
private static final String DEFAULT_LISTEN_HOST = "127.0.0.1";
|
||||
private static final String DEFAULT_WEBAPPS_DIR = "./webapps/";
|
||||
private static final String USAGE = "Bad RouterConsoleRunner arguments, check clientApp.0.args in your clients.config file! " +
|
||||
@ -125,10 +140,12 @@ public class RouterConsoleRunner {
|
||||
* to both, we can't connect to [::1]:7657 for some reason.
|
||||
* So the wise choice is ::1,127.0.0.1
|
||||
*/
|
||||
public RouterConsoleRunner(String args[]) {
|
||||
public RouterConsoleRunner(RouterContext ctx, ClientAppManager mgr, String args[]) {
|
||||
_context = ctx;
|
||||
_mgr = mgr;
|
||||
if (args.length == 0) {
|
||||
// _listenHost and _webAppsDir are defaulted below
|
||||
_listenPort = DEFAULT_LISTEN_PORT;
|
||||
_listenPort = Integer.toString(DEFAULT_LISTEN_PORT);
|
||||
} else {
|
||||
boolean ssl = false;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
@ -161,14 +178,61 @@ public class RouterConsoleRunner {
|
||||
System.err.println(USAGE);
|
||||
throw new IllegalArgumentException(USAGE);
|
||||
}
|
||||
_state = INITIALIZED;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
startTrayApp();
|
||||
RouterConsoleRunner runner = new RouterConsoleRunner(args);
|
||||
runner.startConsole();
|
||||
List<RouterContext> contexts = RouterContext.listContexts();
|
||||
if (contexts == null || contexts.isEmpty())
|
||||
throw new IllegalStateException("no router context");
|
||||
RouterConsoleRunner runner = new RouterConsoleRunner(contexts.get(0), null, args);
|
||||
runner.startup();
|
||||
}
|
||||
|
||||
/////// ClientApp methods
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public void startup() {
|
||||
changeState(STARTING);
|
||||
startTrayApp(_context);
|
||||
startConsole();
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public void shutdown(String[] args) {
|
||||
changeState(STOPPING);
|
||||
try {
|
||||
_server.stop();
|
||||
} catch (Exception ie) {}
|
||||
PortMapper portMapper = _context.portMapper();
|
||||
portMapper.unregister(PortMapper.SVC_CONSOLE);
|
||||
portMapper.unregister(PortMapper.SVC_HTTPS_CONSOLE);
|
||||
changeState(STOPPED);
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public ClientAppState getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public String getName() {
|
||||
return "console";
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public String getDisplayName() {
|
||||
return "Router Console";
|
||||
}
|
||||
|
||||
/////// end ClientApp methods
|
||||
|
||||
private synchronized void changeState(ClientAppState state) {
|
||||
_state = state;
|
||||
if (_mgr != null)
|
||||
_mgr.notify(this, state, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* SInce _server is now static
|
||||
* @return may be null or stopped perhaps
|
||||
@ -178,13 +242,13 @@ public class RouterConsoleRunner {
|
||||
return _server;
|
||||
}
|
||||
|
||||
private static void startTrayApp() {
|
||||
private static void startTrayApp(I2PAppContext ctx) {
|
||||
try {
|
||||
//TODO: move away from routerconsole into a separate application.
|
||||
//ApplicationManager?
|
||||
boolean recentJava = SystemVersion.isJava6();
|
||||
// default false for now
|
||||
boolean desktopguiEnabled = I2PAppContext.getGlobalContext().getBooleanProperty("desktopgui.enabled");
|
||||
boolean desktopguiEnabled = ctx.getBooleanProperty("desktopgui.enabled");
|
||||
if (recentJava && desktopguiEnabled) {
|
||||
//Check if we are in a headless environment, set properties accordingly
|
||||
System.setProperty("java.awt.headless", Boolean.toString(GraphicsEnvironment.isHeadless()));
|
||||
@ -219,7 +283,7 @@ public class RouterConsoleRunner {
|
||||
*</pre>
|
||||
*/
|
||||
public void startConsole() {
|
||||
File workDir = new SecureDirectory(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
|
||||
File workDir = new SecureDirectory(_context.getTempDir(), "jetty-work");
|
||||
boolean workDirRemoved = FileUtil.rmdir(workDir, false);
|
||||
if (!workDirRemoved)
|
||||
System.err.println("ERROR: Unable to remove Jetty temporary work directory");
|
||||
@ -228,7 +292,7 @@ public class RouterConsoleRunner {
|
||||
System.err.println("ERROR: Unable to create Jetty temporary work directory");
|
||||
|
||||
//try {
|
||||
// Log.setLog(new I2PLogger(I2PAppContext.getGlobalContext()));
|
||||
// Log.setLog(new I2PLogger(_context));
|
||||
//} catch (Throwable t) {
|
||||
// System.err.println("INFO: I2P Jetty logging class not found, logging to wrapper log");
|
||||
//}
|
||||
@ -236,7 +300,7 @@ public class RouterConsoleRunner {
|
||||
System.setProperty("org.mortbay.log.class", "net.i2p.jetty.I2PLogger");
|
||||
|
||||
// so Jetty can find WebAppConfiguration
|
||||
System.setProperty("jetty.class.path", I2PAppContext.getGlobalContext().getBaseDir() + "/lib/routerconsole.jar");
|
||||
System.setProperty("jetty.class.path", _context.getBaseDir() + "/lib/routerconsole.jar");
|
||||
_server = new Server();
|
||||
_server.setGracefulShutdown(1000);
|
||||
|
||||
@ -259,11 +323,11 @@ public class RouterConsoleRunner {
|
||||
hColl.addHandler(chColl);
|
||||
hColl.addHandler(new DefaultHandler());
|
||||
|
||||
String log = I2PAppContext.getGlobalContext().getProperty("routerconsole.log");
|
||||
String log = _context.getProperty("routerconsole.log");
|
||||
if (log != null) {
|
||||
File logFile = new File(log);
|
||||
if (!logFile.isAbsolute())
|
||||
logFile = new File(I2PAppContext.getGlobalContext().getLogDir(), "logs/" + log);
|
||||
logFile = new File(_context.getLogDir(), "logs/" + log);
|
||||
try {
|
||||
RequestLogHandler rhl = new RequestLogHandler();
|
||||
rhl.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
|
||||
@ -283,7 +347,7 @@ public class RouterConsoleRunner {
|
||||
// We assume relative to the base install dir for backward compatibility
|
||||
File app = new File(_webAppsDir);
|
||||
if (!app.isAbsolute()) {
|
||||
app = new File(I2PAppContext.getGlobalContext().getBaseDir(), _webAppsDir);
|
||||
app = new File(_context.getBaseDir(), _webAppsDir);
|
||||
try {
|
||||
_webAppsDir = app.getCanonicalPath();
|
||||
} catch (IOException ioe) {}
|
||||
@ -363,7 +427,7 @@ public class RouterConsoleRunner {
|
||||
}
|
||||
}
|
||||
// XXX: what if listenhosts do not include 127.0.0.1? (Should that ever even happen?)
|
||||
I2PAppContext.getGlobalContext().portMapper().register(PortMapper.SVC_CONSOLE,lport);
|
||||
_context.portMapper().register(PortMapper.SVC_CONSOLE,lport);
|
||||
}
|
||||
|
||||
// add SSL listeners
|
||||
@ -376,8 +440,7 @@ public class RouterConsoleRunner {
|
||||
System.err.println("Bad routerconsole SSL port " + _sslListenPort);
|
||||
}
|
||||
if (sslPort > 0) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
File keyStore = new File(ctx.getConfigDir(), "keystore/console.ks");
|
||||
File keyStore = new File(_context.getConfigDir(), "keystore/console.ks");
|
||||
if (verifyKeyStore(keyStore)) {
|
||||
StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
|
||||
while (tok.hasMoreTokens()) {
|
||||
@ -408,9 +471,9 @@ public class RouterConsoleRunner {
|
||||
SslSelectChannelConnector sssll = new SslSelectChannelConnector();
|
||||
// the keystore path and password
|
||||
sssll.setKeystore(keyStore.getAbsolutePath());
|
||||
sssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
||||
sssll.setPassword(_context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
||||
// the X.509 cert password (if not present, verifyKeyStore() returned false)
|
||||
sssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
||||
sssll.setKeyPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
||||
sssll.setUseDirectBuffers(false); // default true seems to be leaky
|
||||
ssll = sssll;
|
||||
} else {
|
||||
@ -418,9 +481,9 @@ public class RouterConsoleRunner {
|
||||
SslSocketConnector sssll = new SslSocketConnector();
|
||||
// the keystore path and password
|
||||
sssll.setKeystore(keyStore.getAbsolutePath());
|
||||
sssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
||||
sssll.setPassword(_context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
||||
// the X.509 cert password (if not present, verifyKeyStore() returned false)
|
||||
sssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
||||
sssll.setKeyPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
||||
ssll = sssll;
|
||||
}
|
||||
ssll.setHost(host);
|
||||
@ -437,7 +500,7 @@ public class RouterConsoleRunner {
|
||||
System.err.println("You may ignore this warning if the console is still available at https://localhost:" + sslPort);
|
||||
}
|
||||
}
|
||||
I2PAppContext.getGlobalContext().portMapper().register(PortMapper.SVC_HTTPS_CONSOLE,sslPort);
|
||||
_context.portMapper().register(PortMapper.SVC_HTTPS_CONSOLE,sslPort);
|
||||
} else {
|
||||
System.err.println("Unable to create or access keystore for SSL: " + keyStore.getAbsolutePath());
|
||||
}
|
||||
@ -448,7 +511,7 @@ public class RouterConsoleRunner {
|
||||
return;
|
||||
}
|
||||
|
||||
rootWebApp = new LocaleWebAppHandler(I2PAppContext.getGlobalContext(),
|
||||
rootWebApp = new LocaleWebAppHandler(_context,
|
||||
"/", _webAppsDir + ROUTERCONSOLE + ".war");
|
||||
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||
@ -458,7 +521,7 @@ public class RouterConsoleRunner {
|
||||
rootWebApp.setSessionHandler(new SessionHandler());
|
||||
rootServletHandler = new ServletHandler();
|
||||
rootWebApp.setServletHandler(rootServletHandler);
|
||||
initialize(rootWebApp);
|
||||
initialize(_context, rootWebApp);
|
||||
chColl.addHandler(rootWebApp);
|
||||
|
||||
} catch (Exception ioe) {
|
||||
@ -495,7 +558,7 @@ public class RouterConsoleRunner {
|
||||
}
|
||||
if (error) {
|
||||
System.err.println("WARNING: Error starting one or more listeners of the Router Console server.\n" +
|
||||
"If your console is still accessible at http://127.0.0.1:7657/,\n" +
|
||||
"If your console is still accessible at http://127.0.0.1:" + _listenPort + "/,\n" +
|
||||
"this may be a problem only with binding to the IPV6 address ::1.\n" +
|
||||
"If so, you may ignore this error, or remove the\n" +
|
||||
"\"::1,\" in the \"clientApp.0.args\" line of the clients.config file.");
|
||||
@ -517,7 +580,7 @@ public class RouterConsoleRunner {
|
||||
if (! "false".equals(enabled)) {
|
||||
try {
|
||||
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
||||
WebAppStarter.startWebApp(I2PAppContext.getGlobalContext(), chColl, appName, path);
|
||||
WebAppStarter.startWebApp(_context, chColl, appName, path);
|
||||
if (enabled == null) {
|
||||
// do this so configclients.jsp knows about all apps from reading the config
|
||||
props.setProperty(PREFIX + appName + ENABLED, "true");
|
||||
@ -532,13 +595,15 @@ public class RouterConsoleRunner {
|
||||
notStarted.add(appName);
|
||||
}
|
||||
}
|
||||
changeState(RUNNING);
|
||||
}
|
||||
} else {
|
||||
System.err.println("ERROR: Router console did not start, not starting webapps");
|
||||
changeState(START_FAILED);
|
||||
}
|
||||
|
||||
if (rewrite)
|
||||
storeWebAppProperties(props);
|
||||
storeWebAppProperties(_context, props);
|
||||
|
||||
if (rootServletHandler != null && notStarted.size() > 0) {
|
||||
// map each not-started webapp to the error page
|
||||
@ -565,35 +630,29 @@ public class RouterConsoleRunner {
|
||||
t.setPriority(Thread.NORM_PRIORITY - 1);
|
||||
t.start();
|
||||
|
||||
List<RouterContext> contexts = RouterContext.listContexts();
|
||||
if (contexts != null) {
|
||||
RouterContext ctx = contexts.get(0);
|
||||
|
||||
ConsoleUpdateManager um = new ConsoleUpdateManager(ctx);
|
||||
ConsoleUpdateManager um = new ConsoleUpdateManager(_context);
|
||||
um.start();
|
||||
|
||||
if (PluginStarter.pluginsEnabled(ctx)) {
|
||||
t = new I2PAppThread(new PluginStarter(ctx), "PluginStarter", true);
|
||||
if (PluginStarter.pluginsEnabled(_context)) {
|
||||
t = new I2PAppThread(new PluginStarter(_context), "PluginStarter", true);
|
||||
t.setPriority(Thread.NORM_PRIORITY - 1);
|
||||
t.start();
|
||||
ctx.addShutdownTask(new PluginStopper(ctx));
|
||||
_context.addShutdownTask(new PluginStopper(_context));
|
||||
}
|
||||
// stat summarizer registers its own hook
|
||||
ctx.addShutdownTask(new ServerShutdown());
|
||||
ConfigServiceHandler.registerSignalHandler(ctx);
|
||||
} // else log CRIT ?
|
||||
_context.addShutdownTask(new ServerShutdown());
|
||||
ConfigServiceHandler.registerSignalHandler(_context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return success if it exists and we have a password, or it was created successfully.
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static boolean verifyKeyStore(File ks) {
|
||||
private boolean verifyKeyStore(File ks) {
|
||||
if (ks.exists()) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
boolean rv = ctx.getProperty(PROP_KEY_PASSWORD) != null;
|
||||
boolean rv = _context.getProperty(PROP_KEY_PASSWORD) != null;
|
||||
if (!rv)
|
||||
System.err.println("Console SSL error, must set " + PROP_KEY_PASSWORD + " in " + (new File(ctx.getConfigDir(), "router.config")).getAbsolutePath());
|
||||
System.err.println("Console SSL error, must set " + PROP_KEY_PASSWORD + " in " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath());
|
||||
return rv;
|
||||
}
|
||||
File dir = ks.getParentFile();
|
||||
@ -614,14 +673,13 @@ public class RouterConsoleRunner {
|
||||
* @return success
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static boolean createKeyStore(File ks) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
private boolean createKeyStore(File ks) {
|
||||
// make a random 48 character password (30 * 8 / 5)
|
||||
byte[] rand = new byte[30];
|
||||
ctx.random().nextBytes(rand);
|
||||
_context.random().nextBytes(rand);
|
||||
String keyPassword = Base32.encode(rand);
|
||||
// and one for the cname
|
||||
ctx.random().nextBytes(rand);
|
||||
_context.random().nextBytes(rand);
|
||||
String cname = Base32.encode(rand) + ".console.i2p.net";
|
||||
|
||||
String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath();
|
||||
@ -643,11 +701,10 @@ public class RouterConsoleRunner {
|
||||
if (success) {
|
||||
SecureFileOutputStream.setPerms(ks);
|
||||
try {
|
||||
RouterContext rctx = (RouterContext) ctx;
|
||||
Map<String, String> changes = new HashMap();
|
||||
changes.put(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
|
||||
changes.put(PROP_KEY_PASSWORD, keyPassword);
|
||||
rctx.router().saveConfig(changes, null);
|
||||
_context.router().saveConfig(changes, null);
|
||||
} catch (Exception e) {} // class cast exception
|
||||
}
|
||||
}
|
||||
@ -664,27 +721,42 @@ public class RouterConsoleRunner {
|
||||
System.err.println(buf.toString());
|
||||
System.err.println("This is for the Sun/Oracle keytool, others may be incompatible.\n" +
|
||||
"If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD +
|
||||
" to " + (new File(ctx.getConfigDir(), "router.config")).getAbsolutePath());
|
||||
" to " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static void initialize(WebAppContext context) {
|
||||
/**
|
||||
* Set up basic security constraints for the webapp.
|
||||
* Add all users and passwords.
|
||||
*/
|
||||
static void initialize(RouterContext ctx, WebAppContext context) {
|
||||
SecurityHandler sec = new SecurityHandler();
|
||||
List<ConstraintMapping> constraints = new ArrayList(4);
|
||||
String password = getPassword();
|
||||
if (password != null) {
|
||||
HashUserRealm realm = new HashUserRealm("i2prouter");
|
||||
realm.put("admin", password);
|
||||
realm.addUserToRole("admin", "routerAdmin");
|
||||
sec.setUserRealm(realm);
|
||||
sec.setAuthenticator(authenticator);
|
||||
Constraint constraint = new Constraint("admin", "routerAdmin");
|
||||
constraint.setAuthenticate(true);
|
||||
ConstraintMapping cm = new ConstraintMapping();
|
||||
cm.setConstraint(constraint);
|
||||
cm.setPathSpec("/");
|
||||
constraints.add(cm);
|
||||
ConsolePasswordManager mgr = new ConsolePasswordManager(ctx);
|
||||
boolean enable = ctx.getBooleanProperty(PROP_PW_ENABLE);
|
||||
if (enable) {
|
||||
Map<String, String> userpw = mgr.getMD5(PROP_CONSOLE_PW);
|
||||
if (userpw.isEmpty()) {
|
||||
enable = false;
|
||||
ctx.router().saveConfig(PROP_CONSOLE_PW, "false");
|
||||
} else {
|
||||
HashUserRealm realm = new HashUserRealm(JETTY_REALM);
|
||||
sec.setUserRealm(realm);
|
||||
sec.setAuthenticator(authenticator);
|
||||
for (Map.Entry<String, String> e : userpw.entrySet()) {
|
||||
String user = e.getKey();
|
||||
String pw = e.getValue();
|
||||
realm.put(user, MD5.__TYPE + pw);
|
||||
realm.addUserToRole(user, JETTY_ROLE);
|
||||
Constraint constraint = new Constraint(user, JETTY_ROLE);
|
||||
constraint.setAuthenticate(true);
|
||||
ConstraintMapping cm = new ConstraintMapping();
|
||||
cm.setConstraint(constraint);
|
||||
cm.setPathSpec("/");
|
||||
constraints.add(cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This forces a '403 Forbidden' response for TRACE and OPTIONS unless the
|
||||
@ -719,24 +791,10 @@ public class RouterConsoleRunner {
|
||||
context.setSecurityHandler(sec);
|
||||
}
|
||||
|
||||
static String getPassword() {
|
||||
List<RouterContext> contexts = RouterContext.listContexts();
|
||||
if (contexts != null) {
|
||||
for (int i = 0; i < contexts.size(); i++) {
|
||||
RouterContext ctx = contexts.get(i);
|
||||
String password = ctx.getProperty("consolePassword");
|
||||
if (password != null) {
|
||||
password = password.trim();
|
||||
if (password.length() > 0) {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no password in any context
|
||||
return null;
|
||||
} else {
|
||||
// no contexts?!
|
||||
return null;
|
||||
/** @since 0.8.8 */
|
||||
private class ServerShutdown implements Runnable {
|
||||
public void run() {
|
||||
shutdown(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -748,14 +806,19 @@ public class RouterConsoleRunner {
|
||||
} catch (Exception ie) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static Properties webAppProperties() {
|
||||
return webAppProperties(I2PAppContext.getGlobalContext().getConfigDir().getAbsolutePath());
|
||||
|
||||
private Properties webAppProperties() {
|
||||
return webAppProperties(_context.getConfigDir().getAbsolutePath());
|
||||
}
|
||||
|
||||
/** @since 0.9.4 */
|
||||
public static Properties webAppProperties(I2PAppContext ctx) {
|
||||
return webAppProperties(ctx.getConfigDir().getAbsolutePath());
|
||||
}
|
||||
|
||||
public static Properties webAppProperties(String dir) {
|
||||
Properties rv = new Properties();
|
||||
// String webappConfigFile = ctx.getProperty(PROP_WEBAPP_CONFIG_FILENAME, DEFAULT_WEBAPP_CONFIG_FILENAME);
|
||||
// String webappConfigFile = _context.getProperty(PROP_WEBAPP_CONFIG_FILENAME, DEFAULT_WEBAPP_CONFIG_FILENAME);
|
||||
String webappConfigFile = DEFAULT_WEBAPP_CONFIG_FILENAME;
|
||||
File cfgFile = new File(dir, webappConfigFile);
|
||||
|
||||
@ -768,10 +831,10 @@ public class RouterConsoleRunner {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static void storeWebAppProperties(Properties props) {
|
||||
// String webappConfigFile = ctx.getProperty(PROP_WEBAPP_CONFIG_FILENAME, DEFAULT_WEBAPP_CONFIG_FILENAME);
|
||||
public static void storeWebAppProperties(RouterContext ctx, Properties props) {
|
||||
// String webappConfigFile = _context.getProperty(PROP_WEBAPP_CONFIG_FILENAME, DEFAULT_WEBAPP_CONFIG_FILENAME);
|
||||
String webappConfigFile = DEFAULT_WEBAPP_CONFIG_FILENAME;
|
||||
File cfgFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), webappConfigFile);
|
||||
File cfgFile = new File(ctx.getConfigDir(), webappConfigFile);
|
||||
|
||||
try {
|
||||
DataHelper.storeProps(props, cfgFile);
|
||||
|
@ -172,6 +172,8 @@ public class SummaryHelper extends HelperBase {
|
||||
//if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
|
||||
// return _("WARN-Firewalled and Fast");
|
||||
return _("Firewalled");
|
||||
case CommSystemFacade.STATUS_DISCONNECTED:
|
||||
return _("Disconnected - check network cable");
|
||||
case CommSystemFacade.STATUS_HOSED:
|
||||
return _("ERR-UDP Port In Use - Set i2np.udp.internalPort=xxxx in advanced config and restart");
|
||||
case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
|
||||
@ -283,11 +285,11 @@ public class SummaryHelper extends HelperBase {
|
||||
*
|
||||
*/
|
||||
/********
|
||||
public int getShitlistedPeers() {
|
||||
public int getBanlistedPeers() {
|
||||
if (_context == null)
|
||||
return 0;
|
||||
else
|
||||
return _context.shitlist().getRouterCount();
|
||||
return _context.banlist().getRouterCount();
|
||||
}
|
||||
********/
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class WebAppConfiguration implements Configuration {
|
||||
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
|
||||
dir = pluginDir;
|
||||
} else {
|
||||
Properties props = RouterConsoleRunner.webAppProperties();
|
||||
Properties props = RouterConsoleRunner.webAppProperties(i2pContext);
|
||||
cp = props.getProperty(RouterConsoleRunner.PREFIX + appName + CLASSPATH);
|
||||
}
|
||||
if (cp == null)
|
||||
|
@ -6,7 +6,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
|
||||
@ -51,7 +51,7 @@ public class WebAppStarter {
|
||||
* adds and starts
|
||||
* @throws just about anything, caller would be wise to catch Throwable
|
||||
*/
|
||||
static void startWebApp(I2PAppContext ctx, ContextHandlerCollection server,
|
||||
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);
|
||||
@ -65,7 +65,7 @@ public class WebAppStarter {
|
||||
* This is used only by RouterConsoleRunner, which adds all the webapps first
|
||||
* and then starts all at once.
|
||||
*/
|
||||
static WebAppContext addWebApp(I2PAppContext ctx, ContextHandlerCollection server,
|
||||
static WebAppContext addWebApp(RouterContext ctx, ContextHandlerCollection server,
|
||||
String appName, String warPath, File tmpdir) throws IOException {
|
||||
|
||||
// Jetty will happily load one context on top of another without stopping
|
||||
@ -103,7 +103,7 @@ public class WebAppStarter {
|
||||
wac.setExtractWAR(false);
|
||||
|
||||
// this does the passwords...
|
||||
RouterConsoleRunner.initialize(wac);
|
||||
RouterConsoleRunner.initialize(ctx, wac);
|
||||
|
||||
// see WebAppConfiguration for info
|
||||
String[] classNames = wac.getConfigurationClasses();
|
||||
|
Reference in New Issue
Block a user