site

(djk)
2011-02-12: Change setting so that the private key isn't displayed unless except

Change setting so that the private key isn't displayed unless except when you enter it.

diff --git a/src/fniki/wiki/ArchiveManager.java b/src/fniki/wiki/ArchiveManager.java
--- a/src/fniki/wiki/ArchiveManager.java
+++ b/src/fniki/wiki/ArchiveManager.java
@@ -75,14 +75,23 @@ public class ArchiveManager {
         FreenetIO.setDebugOutput(out);
     }
 
-    public void setPrivateSSK(String value) {
+    private static void validatePrivateSSK(String value) {
         if (!value.startsWith("SSK@") || !value.endsWith(",AQECAAE/")) {
             throw new IllegalArgumentException("That doesn't look like a private SSK. " +
                                            "Did you forget the trailing '/'?");
         }
+    }
+
+    public void setPrivateSSK(String value) {
+        validatePrivateSSK(value);
         mPrivateSSK = value;
     }
 
+    public String invertPrivateSSK(String value, int timeoutMs) throws IOException {
+        validatePrivateSSK(value);
+        return (new FreenetIO(mFcpHost, mFcpPort)).invertPrivateSSK(value, timeoutMs);
+    }
+
     public String getPrivateSSK() { return mPrivateSSK; }
     public String getParentUri() { return mParentUri; }
 
diff --git a/src/fniki/wiki/WikiApp.java b/src/fniki/wiki/WikiApp.java
--- a/src/fniki/wiki/WikiApp.java
+++ b/src/fniki/wiki/WikiApp.java
@@ -68,9 +68,13 @@ public class WikiApp implements ChildCon
                           ArchiveManager.FMS_GROUP,
                           ArchiveManager.BISS_NAME);
 
+    // Time to wait for FCP before giving up on inverting private key.
+    private final static int INVERT_TIMEOUT_MS = 30 * 1000;
+
     // Delegate to implement link, image and macro handling in wikitext.
     private final FreenetWikiTextParser.ParserDelegate mParserDelegate;
 
+    // ChildContainers for non-modal UI elements.
     private final ChildContainer mDefaultRedirect;
     private final ChildContainer mGotoRedirect;
     private final ChildContainer mQueryError;
@@ -100,7 +104,6 @@ public class WikiApp implements ChildCon
     private String mFormPassword;
     private int mListenPort = LISTEN_PORT;
 
-
     // final because it is called from the ctor.
     private final void resetContentFilter() {
         mFilter = ContentFilterFactory.create(mFproxyPrefix, containerPrefix());
@@ -295,7 +298,6 @@ public class WikiApp implements ChildCon
                     sb.append("{ERROR PROCESSING TITLEINDEX MACRO}");
                     return true;
                 }
-
                 return true;
             }
 
@@ -402,7 +404,7 @@ public class WikiApp implements ChildCon
     // Can return an invalid configuration. e.g. if fms id and private ssk are not set.
     public Configuration getConfiguration() {
         // Converts null values to ""
-        return new Configuration(getInt("listen_port", LISTEN_PORT), //DCI: clean up magic numbers
+        return new Configuration(getInt("listen_port", LISTEN_PORT),
                                  mArchiveManager.getFcpHost(),
                                  mArchiveManager.getFcpPort(),
                                  getString("fproxy_prefix", FPROXY_PREFIX),
@@ -417,6 +419,29 @@ public class WikiApp implements ChildCon
 
     public Configuration getDefaultConfiguration() { return DEFAULT_CONFIG; }
 
+    public String getPublicFmsId(String fmsId, String privateSSK) {
+        if (fmsId == null || privateSSK == null || fmsId.indexOf("@") != -1) {
+            return "???";
+        }
+        try {
+            try {
+                String publicKey = mArchiveManager.invertPrivateSSK(privateSSK, INVERT_TIMEOUT_MS);
+                int pos = publicKey.indexOf(",");
+                if (pos == -1 || pos < 5) {
+                    return "???";
+                }
+                return fmsId + publicKey.substring("SSK".length(), pos);
+
+            } catch (IllegalArgumentException iae) {
+                // Was called with an invalid privateSSK value
+                return "???";
+            }
+        } catch (IOException ioe) {
+            logError("getPublicFmsId failed", ioe);
+            return "???";
+        }
+    }
+
     // For setting data from forms and restoring saved settings.
     // throws unchecked Configuration.ConfigurationException
     public void setConfiguration(Configuration config) {
diff --git a/src/fniki/wiki/WikiContext.java b/src/fniki/wiki/WikiContext.java
--- a/src/fniki/wiki/WikiContext.java
+++ b/src/fniki/wiki/WikiContext.java
@@ -44,6 +44,14 @@ public interface WikiContext extends Req
     Configuration getConfiguration();
     Configuration getDefaultConfiguration();
 
+    // Returns a public fmsId.
+    // e.g. djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks
+    //
+    // fmsId is the human readable part, can be null
+    // private SSK is the private SSK for the FMS identity.
+    // This can return "???" on failure or if the args are null.
+    String getPublicFmsId(String fmsId, String privateSSK);
+
     // throws unchecked Configuration.ConfigurationException
     void setConfiguration(Configuration config);
 
diff --git a/src/fniki/wiki/child/SettingConfig.java b/src/fniki/wiki/child/SettingConfig.java
--- a/src/fniki/wiki/child/SettingConfig.java
+++ b/src/fniki/wiki/child/SettingConfig.java
@@ -44,10 +44,13 @@ public class SettingConfig implements Mo
 
     private boolean mFinished = false;
     private Configuration mConfig;
+    private String mPrivateSSK = "";
+    private String mPublicFmsId = "???";
     private String mMsg = "";
 
     // Doesn't validate.
-    private static Configuration parseConfigFromPost(Query query, int listenPort)  {
+    private Configuration parseConfigFromPost(WikiContext context, Query query,
+                                              int listenPort, String oldSSK)  {
         boolean allowImages = false;
         if (query.containsKey("images")) {
             allowImages = true;
@@ -66,6 +69,13 @@ public class SettingConfig implements Mo
             // NOP
         }
 
+        String newSSK = query.get("fmsssk");
+        if (newSSK == null || newSSK.equals("")) {
+            newSSK = oldSSK;
+        } else {
+            mPublicFmsId = context.getPublicFmsId(query.get("fmsid"), mPrivateSSK);
+        }
+
         Configuration config = new Configuration(listenPort,
                                                  query.get("fcphost"),
                                                  fcpPort,
@@ -74,7 +84,7 @@ public class SettingConfig implements Mo
                                                  query.get("fmshost"),
                                                  fmsPort,
                                                  query.get("fmsid"),
-                                                 query.get("fmsssk"),
+                                                 newSSK,
                                                  query.get("fmsgroup"),
                                                  query.get("wikiname"));
         return config;
@@ -87,7 +97,7 @@ public class SettingConfig implements Mo
             // Pop a save-as dialog for configuration.
             try {
                 // Save any changes the user made.
-                mConfig = parseConfigFromPost(query, context.getInt("listen_port", 8083));
+                mConfig = parseConfigFromPost(context, query, context.getInt("listen_port", 8083), mPrivateSSK);
                 mConfig.validate();
 
                 // Force browser to save the config file to disk.
@@ -113,6 +123,8 @@ public class SettingConfig implements Mo
                 Configuration config = Configuration.fromStringRep(query.get("upload"));
                 config.validate();
                 mConfig = config;
+                mPrivateSSK = mConfig.mFmsSsk;
+                mPublicFmsId = context.getPublicFmsId(mConfig.mFmsId, mConfig.mFmsSsk);
                 mMsg = "Imported configuration!";
                 return;
             } catch (Configuration.ConfigurationException cfe) {
@@ -138,8 +150,8 @@ public class SettingConfig implements Mo
             return;
         }
 
-        mConfig = parseConfigFromPost(query, context.getInt("listen_port", 8083));
-
+        mConfig = parseConfigFromPost(context, query, context.getInt("listen_port", 8083), mPrivateSSK);
+        
         try {
             mConfig.validate();
             context.setConfiguration(mConfig);
@@ -174,8 +186,8 @@ public class SettingConfig implements Mo
                              mConfig.mFproxyPrefix,
                              mConfig.mFmsHost,
                              mConfig.mFmsPort,
-                             mConfig.mFmsSsk,
                              mConfig.mFmsId,
+                             mPublicFmsId,
                              mConfig.mFmsGroup,
                              mConfig.mWikiName,
                              mConfig.mAllowImages ? "checked" : "",
@@ -195,6 +207,8 @@ public class SettingConfig implements Mo
     public void entered(WikiContext context) {
         mFinished = false;
         mConfig = context.getConfiguration();
+        mPrivateSSK = mConfig.mFmsSsk;
+        mPublicFmsId = context.getPublicFmsId(mConfig.mFmsId, mConfig.mFmsSsk);
         mMsg = "";
     }
 
@@ -242,13 +256,17 @@ public class SettingConfig implements Mo
         sb.append("  </tr>\n");
         sb.append("  <tr>\n");
         sb.append("    <td>FMS Private SSK</td>\n");
-        sb.append("    <td><input type=\"text\" name=\"fmsssk\" size=\"128\" value=\"%s\" /> </td>\n");
+        sb.append("    <td><input type=\"text\" name=\"fmsssk\" size=\"128\" value=\"\" /> </td>\n");
         sb.append("  </tr>\n");
         sb.append("  <tr>\n");
-        sb.append("    <td>FMS ID</td>\n");
+        sb.append("    <td>FMS name</td>\n");
         sb.append("    <td><input type=\"text\" name=\"fmsid\" value=\"%s\" /> </td>\n");
         sb.append("  </tr>\n");
         sb.append("  <tr>\n");
+        sb.append("    <td>Full FMS ID</td>\n");
+        sb.append("    <td><input type=\"text\" name=\"fmsfull\" size=\"64\" readonly=\"readonly\" value=\"%s\" /> </td>\n");
+        sb.append("  </tr>\n");
+        sb.append("  <tr>\n");
         sb.append("    <td>FMS Group</td>\n");
         sb.append("    <td><input type=\"text\" name=\"fmsgroup\" value=\"%s\" /> </td>\n");
         sb.append("  </tr>\n");