Hi!

On Thu, Jun 5, 2014 at 6:52 PM, Thomas Mueller <thomas.tom.muel...@gmail.com
> wrote:

> Hi,
>
> I will not have time to implement this feature, but if you want to try,
> please go ahead. Patches are welcome.
>

Sure. I wrote something (attached), let me know what do you think. It gets
allowed by creating an entry "commandHistory" in the properties file. The
whole history gets written into a single line (in order not to spam the
file with up to 1000 lines). The items are separated by semicolons,
original semicolons and backslashes get escaped by backslashes. The history
(if allowed) gets read when the WebServer starts and written after each
command. When multiple consoles get used, the last writer wins.

I'm open for ideas as this is surely not the best way,

 You wrote that it's stored in the *user* home directory and the file is
>> readable by the owner only and that's IMHO about all what can be done for
>> security (encryption by a key stored in a program is pointless and entering
>> the key is too much hassle for such a feature).
>>
>
> I mean, a remote client can see queries that were executed by a different
> remote client. That might be a problem. Encrypting the queries isn't needed
> I think.
>

I see. That's something I didn't think about.

>
> But I can see that it could be a problem for someone, so I'd make it
>> optional.
>>
>
> If you want to implement this feature, yes please make it optional
> (disabled by default).
>

Done.


> That's a bit counter-productive, as I'm doing the same things both locally
>> and on the server, so I can use the same history for both.
>>
>
> OK let's not split the history for now.
>

OK.

Regards,
Martin.

-- 
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to h2-database+unsubscr...@googlegroups.com.
To post to this group, send email to h2-database@googlegroups.com.
Visit this group at http://groups.google.com/group/h2-database.
For more options, visit https://groups.google.com/d/optout.
From b939b058605bd08a5700d553f4d56e7fabaa4cf8 Mon Sep 17 00:00:00 2001
Date: Fri, 13 Jun 2014 19:07:34 +0200
Subject: [PATCH] Persist the web command history optionally.

---
 src/main/org/h2/server/web/WebServer.java  | 61 ++++++++++++++++++++++++++++++
 src/main/org/h2/server/web/WebSession.java | 10 ++++-
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/src/main/org/h2/server/web/WebServer.java b/src/main/org/h2/server/web/WebServer.java
index 70335d7..742e08c 100644
--- a/src/main/org/h2/server/web/WebServer.java
+++ b/src/main/org/h2/server/web/WebServer.java
@@ -49,6 +49,8 @@ import org.h2.util.Utils;
  */
 public class WebServer implements Service {
 
+    private static final String COMMAND_HISTORY = "commandHistory";
+
     static final String TRANSFER = "transfer";
 
     static final String[][] LANGUAGES = {
@@ -158,6 +160,7 @@ public class WebServer implements Service {
     private TranslateThread translateThread;
     private boolean allowChunked = true;
     private String serverPropertiesDir = Constants.SERVER_PROPERTIES_DIR;
+    private String commandHistoryString; // null means the history is not persisted
 
     /**
      * Read the given file from the file system or from the resources.
@@ -292,6 +295,7 @@ public class WebServer implements Service {
                 "webSSL", false);
         allowOthers = SortedProperties.getBooleanProperty(prop,
                 "webAllowOthers", false);
+        commandHistoryString = prop.getProperty(COMMAND_HISTORY);
         for (int i = 0; args != null && i < args.length; i++) {
             String a = args[i];
             if (Tool.isOption(a, "-webPort")) {
@@ -525,6 +529,60 @@ public class WebServer implements Service {
         return port;
     }
 
+    public boolean isCommandHistoryAllowed() {
+        return commandHistoryString != null;
+    }
+
+    public void allowCommandHistory() {
+        if (commandHistoryString == null) {
+            commandHistoryString = "";
+        }
+    }
+
+    public void forbidCommandHistory() {
+        commandHistoryString = null;
+    }
+
+    public ArrayList<String> getCommandHistoryList() {
+        ArrayList<String> result = New.arrayList();
+        if (commandHistoryString == null) {
+            return result;
+        }
+
+        // Split the commandHistoryString on non-escaped semicolons and unescape it.
+        StringBuilder sb = new StringBuilder();
+        for (int end = 0; ; end++) {
+
+            if (end == commandHistoryString.length() || commandHistoryString.charAt(end) == ';') {
+                if (sb.length() > 0) {
+                    result.add(sb.toString());
+                    sb.delete(0, sb.length());
+                }
+                if (end == commandHistoryString.length()) {
+                    break;
+                }
+            } else if (commandHistoryString.charAt(end) == '\\' && end < commandHistoryString.length() - 1) {
+                sb.append(commandHistoryString.charAt(++end));
+            } else {
+                sb.append(commandHistoryString.charAt(end));
+            }
+        }
+
+        return result;
+    }
+
+    public void saveCommandHistoryList(ArrayList<String> commandHistory) {
+        StringBuilder sb = new StringBuilder();
+        for (String s : commandHistory) {
+            if (sb.length() > 0) {
+                sb.append(';');
+            }
+            sb.append(s.replace("\\", "\\\\").replace(";", "\\;"));
+        }
+        commandHistoryString = sb.toString();
+        saveProperties(null);
+    }
+
     /**
      * Get the connection information for this setting.
      *
@@ -633,6 +691,9 @@ public class WebServer implements Service {
                 prop.setProperty("webSSL",
                         "" + SortedProperties.getBooleanProperty(old,
                         "webSSL", ssl));
+                if (commandHistoryString != null) {
+                    prop.setProperty(COMMAND_HISTORY, commandHistoryString);
+                }
             }
             ArrayList<ConnectionInfo> settings = getSettings();
             int len = settings.size();
diff --git a/src/main/org/h2/server/web/WebSession.java b/src/main/org/h2/server/web/WebSession.java
index 7c7b931..ea8255a 100644
--- a/src/main/org/h2/server/web/WebSession.java
+++ b/src/main/org/h2/server/web/WebSession.java
@@ -57,7 +57,10 @@ class WebSession {
 
     private final WebServer server;
 
-    private final ArrayList<String> commandHistory = New.arrayList();
+    private final ArrayList<String> commandHistory;
+    // This must be stored in the session rather than in the server.
+    // Otherwise, one client could allow saving history for others (insecure).
+    private final boolean commandHistoryAllowed;
 
     private Connection conn;
     private DatabaseMetaData meta;
@@ -67,6 +70,8 @@ class WebSession {
 
     WebSession(WebServer server) {
         this.server = server;
+        this.commandHistory = server.getCommandHistoryList();
+        this.commandHistoryAllowed = server.isCommandHistoryAllowed();
     }
 
     /**
@@ -173,6 +178,9 @@ class WebSession {
             commandHistory.remove(idx);
         }
         commandHistory.add(sql);
+        if (commandHistoryAllowed) {
+            server.saveCommandHistoryList(commandHistory);
+        }
     }
 
     /**
-- 
2.0.0

Reply via email to