From c5ab6b9993309a9ce13c860550cc8429182f30bb Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sat, 13 Oct 2012 21:20:16 +0000
Subject: [PATCH]   * Passwords:     - Add remove method     - Add console
 password form to configui.jsp     - Consolidate multiple
 setSettings()/getJettyString() in FormHandler     - Some form message tweaks

---
 .../i2p/router/web/ConfigClientsHandler.java  | 21 +++-----
 .../net/i2p/router/web/ConfigHomeHandler.java | 14 ------
 .../net/i2p/router/web/ConfigNetHandler.java  |  5 +-
 .../i2p/router/web/ConfigReseedHandler.java   | 11 ----
 .../i2p/router/web/ConfigStatsHandler.java    |  5 +-
 .../i2p/router/web/ConfigSummaryHandler.java  | 13 -----
 .../net/i2p/router/web/ConfigUIHandler.java   | 50 ++++++++++++++++++-
 .../net/i2p/router/web/ConfigUIHelper.java    | 37 +++++++++++++-
 .../router/web/ConsolePasswordManager.java    |  4 +-
 .../src/net/i2p/router/web/FormHandler.java   | 25 ++++++++++
 apps/routerconsole/jsp/configui.jsp           | 25 +++++++++-
 .../router/util/RouterPasswordManager.java    | 20 ++++++++
 12 files changed, 167 insertions(+), 63 deletions(-)

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 ff70495241..0dbaaf7fe5 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java
@@ -19,7 +19,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() {
@@ -167,8 +166,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++) {
@@ -212,15 +209,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.
@@ -421,9 +411,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"));
     }
 }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java
index e944f367ec..c8b3d0e745 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigHomeHandler.java
@@ -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();
-    }
 }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
index cd1f103caf..67c47fbb7f 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
@@ -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);
 
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java
index 53da37bc7a..09f7a89343 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java
@@ -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) {
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 07f220f7a0..e867a8b32f 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java
@@ -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>"));
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java
index 7d5c267769..9965f63c30 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java
@@ -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))
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 9616e74b34..da0f41c749 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java
@@ -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,47 @@ 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
+        pw = name + ':' + RouterConsoleRunner.JETTY_REALM + ':' + pw;
+        if (mgr.saveMD5(RouterConsoleRunner.PROP_CONSOLE_PW, name, pw)) {
+            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"));
+    }
 }
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 990572ab48..273c8521d8 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java
@@ -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>&nbsp;</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();
+    }
 }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConsolePasswordManager.java b/apps/routerconsole/java/src/net/i2p/router/web/ConsolePasswordManager.java
index 4d475e43f2..0b320023ab 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConsolePasswordManager.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConsolePasswordManager.java
@@ -173,9 +173,9 @@ public class ConsolePasswordManager extends RouterPasswordManager {
     /**
      *  Straight MD5, no salt
      *
-     *  @param realm e.g. i2cp, routerconsole, etc.
+     *  @param realm The full realm, e.g. routerconsole.auth.i2prouter, etc.
      *  @param user null or "" for no user, already trimmed
-     *  @param pw plain text, already trimmed
+     *  @param pw plain text, must be of the form user:realm:pw to be compatible with Jetty
      *  @return if pw verified
      */
     public boolean saveMD5(String realm, String user, String pw) {
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 6cbfd184a4..4cd8f8d232 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
@@ -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,6 +20,7 @@ import net.i2p.util.Log;
 public class FormHandler {
     protected RouterContext _context;
     protected Log _log;
+    protected Map _settings;
     private String _nonce;
     protected String _action;
     protected String _method;
@@ -52,6 +55,28 @@ public class FormHandler {
     public void setNonce(String val) { _nonce = val; }
     public void setAction(String val) { _action = 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
      *
diff --git a/apps/routerconsole/jsp/configui.jsp b/apps/routerconsole/jsp/configui.jsp
index a2f4397137..3177142da9 100644
--- a/apps/routerconsole/jsp/configui.jsp
+++ b/apps/routerconsole/jsp/configui.jsp
@@ -6,6 +6,13 @@
 <html><head>
 <%@include file="css.jsi" %>
 <%=intl.title("config UI")%>
+<style type='text/css'>
+input.default {
+    width: 1px;
+    height: 1px;
+    visibility: hidden;
+}
+</style>
 <script src="/js/ajax.js" type="text/javascript"></script>
 <%@include file="summaryajax.jsi" %>
 </head><body onload="initAjax()">
@@ -24,6 +31,7 @@
  <% formhandler.storeMethod(request.getMethod()); %>
  <jsp:setProperty name="formhandler" property="*" />
  <jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute(\"i2p.contextId\")%>" />
+ <jsp:setProperty name="formhandler" property="settings" value="<%=request.getParameterMap()%>" />
  <jsp:getProperty name="formhandler" property="allMessages" />
 <div class="configure"><div class="topshimten"><h3><%=uihelper._("Router Console Theme")%></h3></div>
  <form action="" method="POST">
@@ -34,9 +42,10 @@
         consoleNonce = Long.toString(new java.util.Random().nextLong());
         System.setProperty("router.consoleNonce", consoleNonce);
     }
+    String pageNonce = formhandler.getNewNonce();
 %>
  <input type="hidden" name="consoleNonce" value="<%=consoleNonce%>" >
- <input type="hidden" name="nonce" value="<jsp:getProperty name="formhandler" property="newNonce" />" >
+ <input type="hidden" name="nonce" value="<%=pageNonce%>" >
  <input type="hidden" name="action" value="blah" >
 <%
  String userAgent = request.getHeader("User-Agent");
@@ -54,5 +63,17 @@
 </p><hr><div class="formaction">
 <input type="reset" class="cancel" value="<%=intl._("Cancel")%>" >
 <input type="submit" name="shouldsave" class="accept" value="<%=intl._("Apply")%>" >
-</div></form></div>
+</div></form>
+
+<h3><%=uihelper._("Router Console Password")%></h3>
+<form action="" method="POST">
+ <input type="hidden" name="nonce" value="<%=pageNonce%>" >
+ <jsp:getProperty name="uihelper" property="passwordForm" />
+ <div class="formaction">
+  <input type="submit" name="action" class="default" value="<%=intl._("Add user")%>" >
+  <input type="submit" name="action" class="delete" value="<%=intl._("Delete selected")%>" >
+  <input type="reset" class="cancel" value="<%=intl._("Cancel")%>" >
+  <input type="submit" name="action" class="add" value="<%=intl._("Add user")%>" >
+ </div>
+</form></div>
 </div></body></html>
diff --git a/router/java/src/net/i2p/router/util/RouterPasswordManager.java b/router/java/src/net/i2p/router/util/RouterPasswordManager.java
index 966df72822..44bc431e30 100644
--- a/router/java/src/net/i2p/router/util/RouterPasswordManager.java
+++ b/router/java/src/net/i2p/router/util/RouterPasswordManager.java
@@ -164,4 +164,24 @@ public class RouterPasswordManager extends PasswordManager {
         toDel.add(pfx + PROP_CRYPT);
         return _context.router().saveConfig(toAdd, toDel);
     }
+
+    /**
+     *  Remove password, any kind.
+     *
+     *  @param realm e.g. i2cp, routerconsole, etc.
+     *  @param user null or "" for no user, already trimmed
+     *  @return success
+     */
+    public boolean remove(String realm, String user) {
+        String pfx = realm;
+        if (user != null && user.length() > 0)
+            pfx += '.' + user;
+        List<String> toDel = new ArrayList(5);
+        toDel.add(pfx + PROP_PW);
+        toDel.add(pfx + PROP_B64);
+        toDel.add(pfx + PROP_MD5);
+        toDel.add(pfx + PROP_CRYPT);
+        toDel.add(pfx + PROP_SHASH);
+        return _context.router().saveConfig(null, toDel);
+    }
 }
-- 
GitLab