From 03588e76486187f5018dc78723f71338e908b276 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 26 Nov 2017 20:54:44 +0000
Subject: [PATCH] Console: Safer processing of changes on /configadvanced

---
 .../i2p/router/web/ConfigAdvancedHandler.java | 28 ++++++++++++++++---
 apps/routerconsole/jsp/configadvanced.jsp     |  8 ++++--
 2 files changed, 30 insertions(+), 6 deletions(-)

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 f1d621674f..c664362165 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java
@@ -3,6 +3,8 @@ package net.i2p.router.web;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
@@ -17,7 +19,7 @@ import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
 public class ConfigAdvancedHandler extends FormHandler {
     //private boolean _forceRestart;
     private boolean _shouldSave;
-    private String _config;
+    private String _oldConfig, _config;
     private String _ff;
     
     @Override
@@ -44,17 +46,25 @@ public class ConfigAdvancedHandler extends FormHandler {
     public void setNofilter_config(String val) {
         _config = val;
     }
+
+    /** @since 0.9.33 */
+    public void setNofilter_oldConfig(String val) {
+        _oldConfig = val;
+    }
     
     /**
      * The user made changes to the config and wants to save them, so
      * lets go ahead and do so.
      *
+     * We saved the previous config in the form, so we do a diff between the two.
+     * This will reduce the chance of undoing some change that happened in-between.
      */
     private void saveChanges() {
-        Set<String> unsetKeys = new HashSet<String>(_context.router().getConfigSettings());
-        if (_config != null) {
+        if (_oldConfig != null && _config != null) {
+            Properties oldProps = new Properties();
             Properties props = new Properties();
             try {
+                DataHelper.loadProps(oldProps, new ByteArrayInputStream(DataHelper.getUTF8(_oldConfig)));
                 DataHelper.loadProps(props, new ByteArrayInputStream(DataHelper.getUTF8(_config)));
             } catch (IOException ioe) {
                 _log.error("Config error", ioe);
@@ -63,9 +73,19 @@ public class ConfigAdvancedHandler extends FormHandler {
                 return;
             }
 
-            for (String key : props.stringPropertyNames()) {
+            Set<String> unsetKeys = new HashSet<String>(oldProps.stringPropertyNames());
+            for (Iterator<Map.Entry<Object, Object>> iter = props.entrySet().iterator(); iter.hasNext(); ) {
+                Map.Entry<Object, Object> e = iter.next();
+                String key = (String) e.getKey();
+                String nnew = (String) e.getValue();
+                String old = oldProps.getProperty(key);
                 unsetKeys.remove(key);
+                if (nnew.equals(old)) {
+                    // no change
+                    iter.remove();
+                }
             }
+            // what's remaining in unsetKeys will be deleted
 
             boolean saved = _context.router().saveConfig(props, unsetKeys);
             if (saved) 
diff --git a/apps/routerconsole/jsp/configadvanced.jsp b/apps/routerconsole/jsp/configadvanced.jsp
index bc470e8599..00820a098e 100644
--- a/apps/routerconsole/jsp/configadvanced.jsp
+++ b/apps/routerconsole/jsp/configadvanced.jsp
@@ -56,10 +56,14 @@
 </form>
 
 <h3 id="advancedconfig" class="tabletitle"><%=intl._t("Advanced I2P Configuration")%>&nbsp;<a title="Help with additional configuration settings" href="/help#advancedsettings">[Additional Options]</a></h3>
-<% if (advancedhelper.isAdvanced()) { %>
+<%
+  String advConfig = advancedhelper.getSettings();
+  if (advancedhelper.isAdvanced()) {
+%>
  <form action="" method="POST">
  <input type="hidden" name="nonce" value="<%=pageNonce%>" >
  <input type="hidden" name="action" value="blah" >
+ <input type="hidden" name="nofilter_oldConfig" value="<%=advConfig%>" >
 <% }  // isAdvanced %>
 <table class="configtable" id="advconf">
 <% if (advancedhelper.isAdvanced()) { %>
@@ -72,7 +76,7 @@
  </td></tr>
 <% }  // isAdvanced %>
  <tr><td class="tabletextarea">
- <textarea id="advancedsettings" rows="32" cols="60" name="nofilter_config" wrap="off" spellcheck="false" <% if (!advancedhelper.isAdvanced()) { %>readonly="readonly"<% } %>><jsp:getProperty name="advancedhelper" property="settings" /></textarea>
+ <textarea id="advancedsettings" rows="32" cols="60" name="nofilter_config" wrap="off" spellcheck="false" <% if (!advancedhelper.isAdvanced()) { %>readonly="readonly"<% } %>><%=advConfig%></textarea>
  </td></tr>
 <% if (advancedhelper.isAdvanced()) { %>
  <tr><td class="optionsave" align="right">
-- 
GitLab