diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index ba6733bcc6..e929a4a7d5 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -241,7 +241,20 @@ public class SnarkManager implements CompleteListener { private static final int MAX_MESSAGES = 100; + /** + * Use if it does not include a link. + * Escapes '<' and '>' before queueing + */ public void addMessage(String message) { + addMessageNoEscape(message.replace("<", "<").replace(">", ">")); + } + + /** + * Use if it includes a link. + * Does not escape '<' and '>' before queueing + * @since 0.9.14.1 + */ + public void addMessageNoEscape(String message) { _messages.offer(message); while (_messages.size() > MAX_MESSAGES) { _messages.poll(); @@ -579,7 +592,7 @@ public class SnarkManager implements CompleteListener { } if (dataDir != null && !dataDir.equals(getDataDir().getAbsolutePath())) { - dataDir = dataDir.trim(); + dataDir = DataHelper.stripHTML(dataDir.trim()); File dd = new File(dataDir); if (!dd.isAbsolute()) { addMessage(_("Data directory must be an absolute path") + ": " + dataDir); @@ -609,7 +622,7 @@ public class SnarkManager implements CompleteListener { } Map opts = new HashMap(); - if (i2cpOpts == null) i2cpOpts = ""; + i2cpOpts = DataHelper.stripHTML(i2cpOpts); StringTokenizer tok = new StringTokenizer(i2cpOpts, " \t\n"); while (tok.hasMoreTokens()) { String pair = tok.nextToken(); diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 75aa762856..527227081b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -711,7 +711,7 @@ public class I2PSnarkServlet extends BasicServlet { // return; //} if ("Add".equals(action)) { - String newURL = req.getParameter("newURL"); + String newURL = req.getParameter("nofilter_newURL"); /****** // NOTE - newFile currently disabled in HTML form - see below File f = null; @@ -747,7 +747,13 @@ public class I2PSnarkServlet extends BasicServlet { } else *****/ if (newURL != null) { - if (newURL.startsWith("http://")) { + if (newURL.contains("<") || newURL.contains(">") || + newURL.contains("%3C") || newURL.contains("%3E") || + newURL.contains("%3c") || newURL.contains("%3e") || + newURL.contains("\"") || newURL.contains("'") || + newURL.contains("%22") || newURL.contains("%27")) { + _manager.addMessage("Invalid URL"); + } else if (newURL.startsWith("http://")) { FetchAndAdd fetch = new FetchAndAdd(_context, _manager, newURL); _manager.addDownloader(fetch); } else if (newURL.startsWith(MagnetURI.MAGNET) || newURL.startsWith(MagnetURI.MAGGOT)) { @@ -937,7 +943,7 @@ public class I2PSnarkServlet extends BasicServlet { if (k.startsWith("backup_")) { String url = k.substring(7); if (!url.equals(announceURL)) - backupURLs.add(url); + backupURLs.add(DataHelper.stripHTML(url)); } } List> announceList = null; @@ -1036,7 +1042,7 @@ public class I2PSnarkServlet extends BasicServlet { Tracker t; if ((t = trackers.remove(k)) != null) { removed.add(t.announceURL); - _manager.addMessage(_("Removed") + ": " + k); + _manager.addMessage(_("Removed") + ": " + DataHelper.stripHTML(k)); changed = true; } } else if (k.startsWith("open_")) { @@ -1070,9 +1076,9 @@ public class I2PSnarkServlet extends BasicServlet { String hurl = req.getParameter("thurl"); String aurl = req.getParameter("taurl"); if (name != null && hurl != null && aurl != null) { - name = name.trim(); - hurl = hurl.trim(); - aurl = aurl.trim().replace("=", "="); + name = DataHelper.stripHTML(name.trim()); + hurl = DataHelper.stripHTML(hurl.trim()); + aurl = DataHelper.stripHTML(aurl.trim()).replace("=", "="); if (name.length() > 0 && hurl.startsWith("http://") && TrackerClient.isValidAnnounce(aurl)) { Map trackers = _manager.getTrackerMap(); trackers.put(name, new Tracker(name, aurl, hurl)); @@ -1716,7 +1722,7 @@ public class I2PSnarkServlet extends BasicServlet { private void writeAddForm(PrintWriter out, HttpServletRequest req) throws IOException { // display incoming parameter if a GET so links will work - String newURL = req.getParameter("newURL"); + String newURL = req.getParameter("nofilter_newURL"); if (newURL == null || newURL.trim().length() <= 0 || req.getMethod().equals("POST")) newURL = ""; else @@ -1732,13 +1738,13 @@ public class I2PSnarkServlet extends BasicServlet { // don't lose peer setting String peerParam = req.getParameter("p"); if (peerParam != null) - out.write("\n"); + out.write("\n"); out.write("
"); out.write("\"\" "); out.write(_("Add Torrent")); out.write("
\n\n"); + boolean allowEdit = isClientChangeEnabled(); List clients = ClientAppConfig.getClientApps(_context); for (int cur = 0; cur < clients.size(); cur++) { ClientAppConfig ca = clients.get(cur); @@ -117,19 +131,21 @@ public class ConfigClientsHelper extends HelperBase { // dangerous, but allow editing the console args too //"webConsole".equals(ca.clientName) || "Web console".equals(ca.clientName), false, RouterConsoleRunner.class.getName().equals(ca.className), - // description, edit - ca.className + ((ca.args != null) ? " " + ca.args : ""), /* (""+cur).equals(_edit) */ false, + // description + ca.className + ((ca.args != null) ? " " + ca.args : ""), + // edit + allowEdit && (""+cur).equals(_edit), // show edit button, show update button // Don't allow edit if it's running, or else we would lose the "handle" to the ClientApp to stop it. - /* !showStop */ false, false, + allowEdit && !showStop, false, // show stop button showStop, // show delete button, show start button !isConsole, showStart); } - //if ("new".equals(_edit)) - // renderForm(buf, "" + clients.size(), "", false, false, false, false, "", true, false, false, false, false, false); + if (allowEdit && "new".equals(_edit)) + renderForm(buf, "" + clients.size(), "", false, false, false, false, "", true, false, false, false, false, false); buf.append("
"); out.write(_("From URL")); - out.write(": \n"); @@ -1770,7 +1776,7 @@ public class I2PSnarkServlet extends BasicServlet { // don't lose peer setting String peerParam = req.getParameter("p"); if (peerParam != null) - out.write("\n"); + out.write("\n"); out.write(""); out.write("\"\" "); out.write(_("Create Torrent")); @@ -2202,6 +2208,7 @@ public class I2PSnarkServlet extends BasicServlet { /** @since 0.8.13 */ private static String urlEncode(String s) { return s.replace(";", "%3B").replace("&", "&").replace(" ", "%20") + .replace("<", "<").replace(">", ">") .replace("[", "%5B").replace("]", "%5D"); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index fc5ca687b7..1964be4e03 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -927,7 +927,7 @@ public class IndexBean { _newProxyUser = s.trim(); } - public void setProxyPassword(String s) { + public void setNofilter_proxyPassword(String s) { if (s != null) _newProxyPW = s.trim(); } @@ -941,7 +941,7 @@ public class IndexBean { _otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER, s.trim()); } - public void setOutproxyPassword(String s) { + public void setNofilter_outproxyPassword(String s) { if (s != null) _otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, s.trim()); } diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp index e612efaa7f..020871e64e 100644 --- a/apps/i2ptunnel/jsp/editClient.jsp +++ b/apps/i2ptunnel/jsp/editClient.jsp @@ -540,7 +540,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; } - +

@@ -564,7 +564,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; } - +

diff --git a/apps/jetty/java/src/net/i2p/servlet/filters/XSSRequestWrapper.java b/apps/jetty/java/src/net/i2p/servlet/filters/XSSRequestWrapper.java index 494306a6ea..b8b8d39919 100644 --- a/apps/jetty/java/src/net/i2p/servlet/filters/XSSRequestWrapper.java +++ b/apps/jetty/java/src/net/i2p/servlet/filters/XSSRequestWrapper.java @@ -21,14 +21,20 @@ public class XSSRequestWrapper extends HttpServletRequestWrapper { // Adapted from https://owasp-esapi-java.googlecode.com/svn/trunk/configuration/esapi/ESAPI.properties private static final Pattern parameterValuePattern = Pattern.compile("^[\\p{L}\\p{Nd}.,:\\-\\/+=~\\[\\]?@_ \r\n]*$"); private static final Pattern headerValuePattern = Pattern.compile("^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ ]*$"); + private static final String NOFILTER = "nofilter_"; public XSSRequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); } + /** + * Parameter names starting with "nofilter_" will not be filtered. + */ @Override public String[] getParameterValues(String parameter) { String[] values = super.getParameterValues(parameter); + if (parameter.startsWith(NOFILTER)) + return values; if (values == null) { return null; @@ -58,9 +64,14 @@ public class XSSRequestWrapper extends HttpServletRequestWrapper { return encodedValues; } + /** + * Parameter names starting with "nofilter_" will not be filtered. + */ @Override public String getParameter(String parameter) { String value = super.getParameter(parameter); + if (parameter.startsWith(NOFILTER)) + return value; String rv = stripXSS(value, parameterValuePattern); if (value != null && rv == null) { Log log = I2PAppContext.getGlobalContext().logManager().getLog(XSSRequestWrapper.class); @@ -69,6 +80,9 @@ public class XSSRequestWrapper extends HttpServletRequestWrapper { return rv; } + /** + * Parameter names starting with "nofilter_" will not be filtered. + */ @Override public Map getParameterMap() { Map rv = new HashMap(); diff --git a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java index d532a9c5c6..316bce65a0 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java @@ -54,6 +54,7 @@ class PluginUpdateRunner extends UpdateRunner { private static final String XPI2P = "app.xpi2p"; private static final String ZIP = XPI2P + ".zip"; public static final String PLUGIN_DIR = PluginStarter.PLUGIN_DIR; + private static final String PROP_ALLOW_NEW_KEYS = "routerconsole.allowUntrustedPlugins"; public PluginUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List uris, String appName, String oldVersion ) { @@ -162,7 +163,7 @@ class PluginUpdateRunner extends UpdateRunner { // ok, now we check sigs and deal with a bad sig String pubkey = props.getProperty("key"); - String signer = props.getProperty("signer"); + String signer = DataHelper.stripHTML(props.getProperty("signer")); if (pubkey == null || signer == null || pubkey.length() != 172 || signer.length() <= 0) { f.delete(); to.delete(); @@ -179,6 +180,14 @@ class PluginUpdateRunner extends UpdateRunner { up.addKey(e.getKey(), e.getValue()); } + // add all trusted plugin keys, so any conflicts with trusted keys + // will be discovered and rejected + Map trustedKeys = TrustedPluginKeys.getKeys(); + for (Map.Entry e : trustedKeys.entrySet()) { + // ignore dups/bad keys + up.addKey(e.getKey(), e.getValue()); + } + if (up.haveKey(pubkey)) { // the key is already in the TrustedUpdate keyring // verify the sig and verify that it is signed by the signer in the plugin.config file @@ -194,7 +203,7 @@ class PluginUpdateRunner extends UpdateRunner { statusDone("" + _("Plugin signature verification of {0} failed", url) + ""); return; } - } else { + } else if (_context.getBooleanProperty(PROP_ALLOW_NEW_KEYS)) { // add to keyring... if(!up.addKey(pubkey, signer)) { // bad or duplicate key @@ -218,6 +227,14 @@ class PluginUpdateRunner extends UpdateRunner { statusDone("" + _("Plugin signature verification of {0} failed", url) + ""); return; } + } else { + // unknown key + f.delete(); + to.delete(); + _log.error("Untrusted plugin key \"" + pubkey + "\" for plugin signer \"" + signer + "\""); + // don't display signer, we're really checking the key not the signer name + statusDone("" + _("Plugin not installed - signer is untrusted") + ""); + return; } String sudVersion = TrustedUpdate.getVersionString(f); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java index 622e655981..a13a432f2c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java @@ -57,7 +57,8 @@ public class CSSHelper extends HelperBase { */ public void setLang(String lang) { // Protected with nonce in css.jsi - if (lang != null && lang.length() > 0 && lang.length() <= 6) { + if (lang != null && lang.length() >= 2 && lang.length() <= 6 && + lang.replaceAll("[a-zA-Z_]", "").length() == 0) { Map m = new HashMap(2); int under = lang.indexOf('_'); if (under < 0) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java index 193334d84e..e5db97f116 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java @@ -21,8 +21,10 @@ public class ConfigAdvancedHandler extends FormHandler { @Override protected void processForm() { if (_shouldSave) { - //saveChanges(); - addFormError("Save disabled, edit the router.config file to make changes") ; + if (isAdvanced()) + saveChanges(); + else + addFormError("Save disabled, edit the router.config file to make changes") ; } else { // noop } @@ -31,7 +33,7 @@ public class ConfigAdvancedHandler extends FormHandler { public void setShouldsave(String moo) { _shouldSave = true; } //public void setRestart(String moo) { _forceRestart = true; } - public void setConfig(String val) { + public void setNofilter_config(String val) { _config = val; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java index d42934e9f2..02f9b05cb2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java @@ -3,6 +3,7 @@ package net.i2p.router.web; import java.util.Map; import java.util.TreeMap; +import net.i2p.data.DataHelper; public class ConfigAdvancedHelper extends HelperBase { public ConfigAdvancedHelper() {} @@ -12,8 +13,8 @@ public class ConfigAdvancedHelper extends HelperBase { TreeMap sorted = new TreeMap(); sorted.putAll(_context.router().getConfigMap()); for (Map.Entry e : sorted.entrySet()) { - String name = e.getKey(); - String val = e.getValue(); + String name = DataHelper.escapeHTML(e.getKey()); + String val = DataHelper.escapeHTML(e.getValue()); buf.append(name).append('=').append(val).append('\n'); } return buf.toString(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java index 464aabb020..5acdf313b2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java @@ -49,17 +49,28 @@ public class ConfigClientsHandler extends FormHandler { saveWebAppChanges(); return; } + boolean pluginsEnabled = PluginStarter.pluginsEnabled(_context); if (_action.equals(_("Save Plugin Configuration"))) { - savePluginChanges(); + if (pluginsEnabled) + savePluginChanges(); + else + addFormError("Plugins disabled"); return; } if (_action.equals(_("Install Plugin"))) { - //installPlugin(); - addFormError("Plugin installation disabled"); + if (pluginsEnabled && + (_context.getBooleanProperty(ConfigClientsHelper.PROP_ENABLE_PLUGIN_INSTALL) || + isAdvanced())) + installPlugin(); + else + addFormError("Plugins disabled"); return; } if (_action.equals(_("Update All Installed Plugins"))) { - updateAllPlugins(); + if (pluginsEnabled) + updateAllPlugins(); + else + addFormError("Plugins disabled"); return; } // value @@ -73,10 +84,14 @@ public class ConfigClientsHandler extends FormHandler { startClient(appnum); } else { List plugins = PluginStarter.getPlugins(); - if (plugins.contains(app)) - startPlugin(app); - else + if (plugins.contains(app)) { + if (pluginsEnabled) + startPlugin(app); + else + addFormError("Plugins disabled"); + } else { startWebApp(app); + } } return; } @@ -90,7 +105,7 @@ public class ConfigClientsHandler extends FormHandler { } catch (NumberFormatException nfe) {} if (appnum >= 0) { deleteClient(appnum); - } else { + } else if (pluginsEnabled) { try { PluginStarter.stopPlugin(_context, app); } catch (ClassNotFoundException cnfe) { @@ -108,6 +123,8 @@ public class ConfigClientsHandler extends FormHandler { addFormError(_("Error deleting plugin {0}", app) + ": " + e); _log.error("Error deleting plugin " + app, e); } + } else { + addFormError("Plugins disabled"); } return; } @@ -126,8 +143,12 @@ public class ConfigClientsHandler extends FormHandler { List plugins = PluginStarter.getPlugins(); if (plugins.contains(app)) { try { - PluginStarter.stopPlugin(_context, app); - addFormNotice(_("Stopped plugin {0}", app)); + if (pluginsEnabled) { + PluginStarter.stopPlugin(_context, app); + addFormNotice(_("Stopped plugin {0}", app)); + } else { + addFormError("Plugins disabled"); + } } catch (Throwable e) { addFormError(_("Error stopping plugin {0}", app) + ": " + e); _log.error("Error stopping plugin " + app, e); @@ -142,15 +163,23 @@ public class ConfigClientsHandler extends FormHandler { // value if (_action.startsWith("Update ")) { - String app = _action.substring(7); - updatePlugin(app); + if (pluginsEnabled) { + String app = _action.substring(7); + updatePlugin(app); + } else { + addFormError("Plugins disabled"); + } return; } // value if (_action.startsWith("Check ")) { - String app = _action.substring(6); - checkPlugin(app); + if (pluginsEnabled) { + String app = _action.substring(6); + checkPlugin(app); + } else { + addFormError("Plugins disabled"); + } return; } @@ -168,10 +197,14 @@ public class ConfigClientsHandler extends FormHandler { startClient(appnum); } else { List plugins = PluginStarter.getPlugins(); - if (plugins.contains(app)) - startPlugin(app); - else + if (plugins.contains(app)) { + if (pluginsEnabled) + startPlugin(app); + else + addFormError("Plugins disabled"); + } else { startWebApp(app); + } } } else { //addFormError(_("Unsupported") + ' ' + _action + '.'); @@ -187,45 +220,46 @@ public class ConfigClientsHandler extends FormHandler { if (! (RouterConsoleRunner.class.getName().equals(ca.className))) ca.disabled = val == null; // edit of an existing entry - // disabled -/**** - String desc = getJettyString("desc" + cur); - if (desc != null) { - int spc = desc.indexOf(" "); - String clss = desc; - String args = null; - if (spc >= 0) { - clss = desc.substring(0, spc); - args = desc.substring(spc + 1); + if (_context.getBooleanProperty(ConfigClientsHelper.PROP_ENABLE_CLIENT_CHANGE) || + isAdvanced()) { + String desc = getJettyString("desc" + cur); + if (desc != null) { + int spc = desc.indexOf(" "); + String clss = desc; + String args = null; + if (spc >= 0) { + clss = desc.substring(0, spc); + args = desc.substring(spc + 1); + } + ca.className = clss; + ca.args = args; + ca.clientName = getJettyString("name" + cur); } - ca.className = clss; - ca.args = args; - ca.clientName = getJettyString("name" + cur); } -****/ } - // disabled -/**** - int newClient = clients.size(); - String newDesc = getJettyString("desc" + newClient); - if (newDesc != null && newDesc.trim().length() > 0) { - // new entry - int spc = newDesc.indexOf(" "); - String clss = newDesc; - String args = null; - if (spc >= 0) { - clss = newDesc.substring(0, spc); - args = newDesc.substring(spc + 1); + // new client + if (_context.getBooleanProperty(ConfigClientsHelper.PROP_ENABLE_CLIENT_CHANGE) || + isAdvanced()) { + int newClient = clients.size(); + String newDesc = getJettyString("desc" + newClient); + if (newDesc != null && newDesc.trim().length() > 0) { + // new entry + int spc = newDesc.indexOf(" "); + String clss = newDesc; + String args = null; + if (spc >= 0) { + clss = newDesc.substring(0, spc); + args = newDesc.substring(spc + 1); + } + String name = getJettyString("name" + newClient); + if (name == null || name.trim().length() <= 0) name = "new client"; + ClientAppConfig ca = new ClientAppConfig(clss, name, args, 2*60*1000, + _settings.get(newClient + ".enabled") != null); + clients.add(ca); + addFormNotice(_("New client added") + ": " + name + " (" + clss + ")."); } - String name = getJettyString("name" + newClient); - if (name == null || name.trim().length() <= 0) name = "new client"; - ClientAppConfig ca = new ClientAppConfig(clss, name, args, 2*60*1000, - _settings.get(newClient + ".enabled") != null); - clients.add(ca); - addFormNotice(_("New client added") + ": " + name + " (" + clss + ")."); } -****/ ClientAppConfig.writeClientAppConfig(_context, clients); addFormNotice(_("Client configuration saved successfully")); @@ -330,7 +364,7 @@ public class ConfigClientsHandler extends FormHandler { File path = new File(_context.getBaseDir(), "webapps"); path = new File(path, app + ".war"); WebAppStarter.startWebApp(_context, s, app, path.getAbsolutePath()); - addFormNotice(_("WebApp") + " " + _(app) + " " + _("started") + '.'); + addFormNoticeNoEscape(_("WebApp") + " " + _(app) + " " + _("started") + '.'); } catch (Throwable e) { addFormError(_("Failed to start") + ' ' + _(app) + " " + e + '.'); _log.error("Failed to start webapp " + app, e); @@ -440,7 +474,7 @@ public class ConfigClientsHandler extends FormHandler { if (intfc != null) changes.put(ClientManagerFacadeImpl.PROP_CLIENT_HOST, intfc); String user = getJettyString("user"); - String pw = getJettyString("pw"); + String pw = getJettyString("nofilter_pw"); if (user != null && pw != null && user.length() > 0 && pw.length() > 0) { ConsolePasswordManager mgr = new ConsolePasswordManager(_context); mgr.saveHash(ConfigClientsHelper.PROP_AUTH, user, pw); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java index cd30f5df1a..843fef7373 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java @@ -26,9 +26,22 @@ 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_ENABLE_CLIENT_CHANGE = "routerconsole.enableClientChange"; + public static final String PROP_ENABLE_PLUGIN_INSTALL = "routerconsole.enablePluginInstall"; public ConfigClientsHelper() {} + /** @since 0.9.14.1 */ + public boolean isClientChangeEnabled() { + return _context.getBooleanProperty(PROP_ENABLE_CLIENT_CHANGE) || isAdvanced(); + } + + /** @since 0.9.14.1 */ + public boolean isPluginInstallEnabled() { + return PluginStarter.pluginsEnabled(_context) && + (_context.getBooleanProperty(PROP_ENABLE_PLUGIN_INSTALL) || isAdvanced()); + } + /** @since 0.8.3 */ public String getPort() { return _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_PORT, @@ -96,6 +109,7 @@ public class ConfigClientsHelper extends HelperBase { .append(_("Control")).append("
") .append(_("Class and arguments")).append("
\n"); return buf.toString(); } @@ -291,9 +307,9 @@ public class ConfigClientsHelper extends HelperBase { if (showStopButton && (!edit)) buf.append(""); - //if (showEditButton && (!edit) && !ro) - // buf.append(""); + if (isClientChangeEnabled() && showEditButton && (!edit) && !ro) + buf.append(""); if (showUpdateButton && (!edit) && !ro) { buf.append(""); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHelper.java index 67b409fb90..b38350fb74 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHelper.java @@ -26,7 +26,7 @@ public class ConfigReseedHelper extends HelperBase { } /** @since 0.8.9 */ - public String getPassword() { + public String getNofilter_password() { return _context.getProperty(Reseeder.PROP_PROXY_PASSWORD, ""); } @@ -46,7 +46,7 @@ public class ConfigReseedHelper extends HelperBase { } /** @since 0.8.9 */ - public String getSpassword() { + public String getNofilter_spassword() { return _context.getProperty(Reseeder.PROP_SPROXY_PASSWORD, ""); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java index 5dcff89de4..39dabd77ce 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java @@ -122,7 +122,7 @@ public class ConfigStatsHandler extends FormHandler { addFormNotice(_("Restart required to take effect")); } if (graphsChanged) - addFormNotice(_("Graph list updated, may take up to 60s to be reflected on the {0}Graphs Page{1}", "", "")); + addFormNoticeNoEscape(_("Graph list updated, may take up to 60s to be reflected on the {0}Graphs Page{1}", "", "")); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java index f20c21367a..e9de89c315 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java @@ -35,8 +35,12 @@ public class ConfigUIHandler extends FormHandler { /** note - lang change is handled in CSSHelper but we still need to save it here */ private void saveChanges() { - if (_config == null) + if (_config == null || _config.length() <= 0) return; + if (_config.replaceAll("[a-zA-Z0-9_-]", "").length() != 0) { + addFormError("Bad theme name"); + return; + } Map changes = new HashMap(); List removes = new ArrayList(); String oldTheme = _context.getProperty(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME); @@ -76,7 +80,7 @@ public class ConfigUIHandler extends FormHandler { addFormError(_("No user name entered")); return; } - String pw = getJettyString("pw"); + String pw = getJettyString("nofilter_pw"); if (pw == null || pw.length() <= 0) { addFormError(_("No password entered")); return; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java index 770ffab2b9..e979587810 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java @@ -183,7 +183,7 @@ public class ConfigUIHelper extends HelperBase { "" + ""); buf.append(_("Password")).append(": " + - "" + + "" + "\n"); return buf.toString(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java index fc1e8fad9e..b1fb3379c9 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java @@ -173,11 +173,14 @@ public class ConfigUpdateHandler extends FormHandler { _newsThroughProxy = false; String oldURL = ConfigUpdateHelper.getNewsURL(_context); if ( (oldURL == null) || (!_newsURL.equals(oldURL)) ) { - //changes.put(PROP_NEWS_URL, _newsURL); - // this invalidates the news - //changes.put(NewsHelper.PROP_LAST_CHECKED, "0"); - //addFormNotice(_("Updating news URL to {0}", _newsURL)); - addFormError("Changing news URL disabled"); + if (isAdvanced()) { + changes.put(PROP_NEWS_URL, _newsURL); + // this invalidates the news + changes.put(NewsHelper.PROP_LAST_CHECKED, "0"); + addFormNotice(_("Updating news URL to {0}", _newsURL)); + } else { + addFormError("Changing news URL disabled"); + } } } @@ -199,7 +202,8 @@ public class ConfigUpdateHandler extends FormHandler { changes.put(PROP_SHOULD_PROXY, Boolean.toString(_updateThroughProxy)); changes.put(PROP_SHOULD_PROXY_NEWS, Boolean.toString(_newsThroughProxy)); - changes.put(PROP_UPDATE_UNSIGNED, Boolean.toString(_updateUnsigned)); + if (isAdvanced()) + changes.put(PROP_UPDATE_UNSIGNED, Boolean.toString(_updateUnsigned)); String oldFreqStr = _context.getProperty(PROP_REFRESH_FREQUENCY, DEFAULT_REFRESH_FREQUENCY); long oldFreq = DEFAULT_REFRESH_FREQ; @@ -233,17 +237,24 @@ public class ConfigUpdateHandler extends FormHandler { oldKeys = oldKeys.replace("\r\n", ","); if (!_trustedKeys.equals(oldKeys)) { // note that keys are not validated here and no console error message will be generated - changes.put(PROP_TRUSTED_KEYS, _trustedKeys); - addFormNotice(_("Updating trusted keys.")); + if (isAdvanced()) { + changes.put(PROP_TRUSTED_KEYS, _trustedKeys); + addFormNotice(_("Updating trusted keys.")); + } else { + addFormError("Changing trusted keys disabled"); + } } } if ( (_zipURL != null) && (_zipURL.length() > 0) ) { String oldURL = _context.router().getConfigSetting(PROP_ZIP_URL); if ( (oldURL == null) || (!_zipURL.equals(oldURL)) ) { - //changes.put(PROP_ZIP_URL, _zipURL); - //addFormNotice(_("Updating unsigned update URL to {0}", _zipURL)); - addFormError("Changing unsigned update URL disabled"); + if (isAdvanced()) { + changes.put(PROP_ZIP_URL, _zipURL); + addFormNotice(_("Updating unsigned update URL to {0}", _zipURL)); + } else { + addFormError("Changing unsigned update URL disabled"); + } } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java index cb3d68e194..5d66bd5a10 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java @@ -51,8 +51,8 @@ public abstract class FormHandler { } } - public void setNonce(String val) { _nonce = DataHelper.stripHTML(val); } - public void setAction(String val) { _action = DataHelper.stripHTML(val); } + public void setNonce(String val) { _nonce = val == null ? null : DataHelper.stripHTML(val); } + public void setAction(String val) { _action = val == null ? null : DataHelper.stripHTML(val); } /** * For many forms, it's easiest just to put all the parameters here. @@ -61,6 +61,14 @@ public abstract class FormHandler { */ public void setSettings(Map settings) { _settings = new HashMap(settings); } + /** + * Same as HelperBase + * @since 0.9.14.1 + */ + public boolean isAdvanced() { + return _context.getBooleanProperty(HelperBase.PROP_ADVANCED); + } + /** * setSettings() must have been called previously * Curses Jetty for returning arrays. @@ -102,16 +110,31 @@ public abstract class FormHandler { /** * Add an error message to display + * Use if it does not include a link. + * Escapes '<' and '>' before queueing */ protected void addFormError(String errorMsg) { if (errorMsg == null) return; - _errors.add(errorMsg); + _errors.add(DataHelper.escapeHTML(errorMsg)); } /** * Add a non-error message to display + * Use if it does not include a link. + * Escapes '<' and '>' before queueing */ protected void addFormNotice(String msg) { + if (msg == null) return; + _notices.add(DataHelper.escapeHTML(msg)); + } + + /** + * Add a non-error message to display + * Use if it includes a link or other formatting. + * Does not escape '<' and '>' before queueing + * @since 0.9.14.1 + */ + protected void addFormNoticeNoEscape(String msg) { if (msg == null) return; _notices.add(msg); } @@ -180,7 +203,7 @@ public abstract class FormHandler { } // To prevent actions with GET, jsps must call storeMethod() if (_method != null && !"POST".equals(_method)) { - addFormError("Invalid form submission, requires POST not " + _method); + addFormError("Invalid form submission, requires POST"); _valid = false; return; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index ff7883c8fb..e2f2ea0af1 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -818,19 +818,19 @@ public class SummaryHelper extends HelperBase { /* below here is stuff we need to get from summarynoframe.jsp to SummaryBarRenderer */ private String _action; - public void setAction(String s) { _action = DataHelper.stripHTML(s); } + public void setAction(String s) { _action = s == null ? null : DataHelper.stripHTML(s); } public String getAction() { return _action; } private String _consoleNonce; - public void setConsoleNonce(String s) { _consoleNonce = DataHelper.stripHTML(s); } + public void setConsoleNonce(String s) { _consoleNonce = s == null ? null : DataHelper.stripHTML(s); } public String getConsoleNonce() { return _consoleNonce; } private String _updateNonce; - public void setUpdateNonce(String s) { _updateNonce = DataHelper.stripHTML(s); } + public void setUpdateNonce(String s) { _updateNonce = s == null ? null : DataHelper.stripHTML(s); } public String getUpdateNonce() { return _updateNonce; } private String _requestURI; - public void setRequestURI(String s) { _requestURI = DataHelper.stripHTML(s); } + public void setRequestURI(String s) { _requestURI = s == null ? null : DataHelper.stripHTML(s); } /** * @return non-null; "/home" if (strangely) not set by jsp diff --git a/apps/routerconsole/jsp/configadvanced.jsp b/apps/routerconsole/jsp/configadvanced.jsp index bdd7108a5f..12389fa2d4 100644 --- a/apps/routerconsole/jsp/configadvanced.jsp +++ b/apps/routerconsole/jsp/configadvanced.jsp @@ -24,19 +24,20 @@ <%@include file="formhandler.jsi" %>
- +<% } // isAdvanced %>

<%=intl._("Advanced I2P Configuration")%>

-

- +<% } else { %> To make changes, edit the router.config file. +<% } // isAdvanced %>
diff --git a/apps/routerconsole/jsp/configclients.jsp b/apps/routerconsole/jsp/configclients.jsp index 82dcf9dbca..8bbfef188f 100644 --- a/apps/routerconsole/jsp/configclients.jsp +++ b/apps/routerconsole/jsp/configclients.jsp @@ -39,7 +39,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; } <%=intl._("All changes require restart to take effect.")%>


" /> -<% if (false && request.getParameter("edit") == null) { %> +<% if (clientshelper.isClientChangeEnabled() && request.getParameter("edit") == null) { %> " /> <% } %> " /> @@ -80,7 +80,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; } <%=intl._("Username")%>:
<%=intl._("Password")%>: -
+

<%=intl._("The default settings will work for most people.")%> <%=intl._("Any changes made here must also be configured in the external client.")%> <%=intl._("Many clients do not support SSL or authorization.")%> @@ -117,7 +117,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; } " />

- -<% } %> +<% + } // pluginInstallEnabled + } // showPlugins +%> diff --git a/apps/routerconsole/jsp/configreseed.jsp b/apps/routerconsole/jsp/configreseed.jsp index 3e306c7584..da667ace1d 100644 --- a/apps/routerconsole/jsp/configreseed.jsp +++ b/apps/routerconsole/jsp/configreseed.jsp @@ -52,7 +52,7 @@ <%=intl._("HTTP Proxy Username")%>: " > <%=intl._("HTTP Proxy Password")%>: -" > +" > diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index 904941b758..68d661e82a 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -41,7 +41,7 @@ <% } %>
<%=intl._("News URL")%>: - "> + readonly="readonly"<% } %> value=""> <%=intl._("Refresh frequency")%>: <% if (updatehelper.canInstall()) { %> @@ -64,13 +64,11 @@ <%=intl._("Trusted keys")%>: - <% } // if isAdvanced %> - + <% } // if isAdvanced %> <% } else { %> <%=intl._("Updates will be dispatched via your package manager.")%> <% } // if canInstall %> diff --git a/apps/routerconsole/jsp/flags.jsp b/apps/routerconsole/jsp/flags.jsp index 92d180289c..b88b37b464 100644 --- a/apps/routerconsole/jsp/flags.jsp +++ b/apps/routerconsole/jsp/flags.jsp @@ -12,7 +12,9 @@ * with headers set so the browser caches. */ String c = request.getParameter("c"); -if (c != null && c.length() > 0) { +if (c != null && + (c.length() == 2 || c.length() == 7) && + c.replaceAll("[a-z_]", "").length() == 0) { java.io.OutputStream cout = response.getOutputStream(); String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath(); String file = "docs" + java.io.File.separatorChar + "icons" + java.io.File.separatorChar + diff --git a/apps/routerconsole/jsp/viewprofile.jsp b/apps/routerconsole/jsp/viewprofile.jsp index ff621d92b6..c353bbaf60 100644 --- a/apps/routerconsole/jsp/viewprofile.jsp +++ b/apps/routerconsole/jsp/viewprofile.jsp @@ -14,10 +14,11 @@
<% String peerB64 = request.getParameter("peer"); - if (peerB64 == null || peerB64.length() <= 0) { + if (peerB64 == null || peerB64.length() <= 0 || + peerB64.replaceAll("[a-zA-Z0-9~=-]", "").length() != 0) { out.print("No peer specified"); } else { - peerB64 = net.i2p.data.DataHelper.stripHTML(peerB64); // XSS + %> " /> diff --git a/history.txt b/history.txt index 83c6e9c0fc..6fc4068f33 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,14 @@ +2014-08-03 zzz + * Console: + - Fix update buttons + - Don't filter parameter names starting with "nofilter_" + - Re-allow configadvanced, news URL, and unsigned update URL if routerconsole.advanced=true + - Re-allow plugin install if routerconsole.advanced=true or routerconsole.enablePluginInstall=true + - Only allow whitelisted plugin signers, unless routerconsole.allowUntrustedPlugins=true + - Re-allow clients.config changes if routerconsole.advanced=true or routerconsole.enableClientChange=true + - More escaping + * i2psnark: Fix add torrent form + 2014-07-31 zzz * ExecNamingService: Remove * Plugins: Add whitelist of keys diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 87e5bffca0..416f035746 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,10 +18,10 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 1; + public final static long BUILD = 2; /** for example "-test" */ - public final static String EXTRA = ""; + public final static String EXTRA = "-rc"; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; public static void main(String args[]) { System.out.println("I2P Router version: " + FULL_VERSION);