Change FCP access rules to a tri-state.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 11 May 2011 04:09:50 +0000 (06:09 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Wed, 11 May 2011 04:11:36 +0000 (06:11 +0200)
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java
src/main/java/net/pterodactylus/sone/web/OptionsPage.java
src/main/resources/i18n/sone.en.properties
src/main/resources/templates/options.html

index 1860473..cfe53ea 100644 (file)
@@ -38,6 +38,7 @@ import net.pterodactylus.sone.data.Profile.Field;
 import net.pterodactylus.sone.data.Reply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.fcp.FcpInterface;
+import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
 import net.pterodactylus.sone.freenet.wot.Identity;
 import net.pterodactylus.sone.freenet.wot.IdentityListener;
 import net.pterodactylus.sone.freenet.wot.IdentityManager;
@@ -1707,7 +1708,7 @@ public class Core implements IdentityListener, UpdateListener {
                        configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal());
                        configuration.getStringValue("Option/TrustComment").setValue(options.getStringOption("TrustComment").getReal());
                        configuration.getBooleanValue("Option/ActivateFcpInterface").setValue(options.getBooleanOption("ActivateFcpInterface").getReal());
-                       configuration.getBooleanValue("Option/FcpWriteFromFullAccessOnly").setValue(options.getBooleanOption("FcpWriteFromFullAccessOnly").getReal());
+                       configuration.getIntValue("Option/FcpFullAccessRequired").setValue(options.getIntegerOption("FcpFullAccessRequired").getReal());
                        configuration.getBooleanValue("Option/SoneRescueMode").setValue(options.getBooleanOption("SoneRescueMode").getReal());
                        configuration.getBooleanValue("Option/ClearOnNextRestart").setValue(options.getBooleanOption("ClearOnNextRestart").getReal());
                        configuration.getBooleanValue("Option/ReallyClearOnNextRestart").setValue(options.getBooleanOption("ReallyClearOnNextRestart").getReal());
@@ -1790,12 +1791,12 @@ public class Core implements IdentityListener, UpdateListener {
                                fcpInterface.setActive(newValue);
                        }
                }));
-               options.addBooleanOption("FcpWriteFromFullAccessOnly", new DefaultOption<Boolean>(true, new OptionWatcher<Boolean>() {
+               options.addIntegerOption("FcpFullAccessRequired", new DefaultOption<Integer>(2, new OptionWatcher<Integer>() {
 
                        @Override
                        @SuppressWarnings("synthetic-access")
-                       public void optionChanged(Option<Boolean> option, Boolean oldValue, Boolean newValue) {
-                               fcpInterface.setAllowWriteFromFullAccessOnly(newValue);
+                       public void optionChanged(Option<Integer> option, Integer oldValue, Integer newValue) {
+                               fcpInterface.setFullAccessRequired(FullAccessRequired.values()[newValue]);
                        }
 
                }));
@@ -1820,7 +1821,7 @@ public class Core implements IdentityListener, UpdateListener {
                options.getIntegerOption("NegativeTrust").set(configuration.getIntValue("Option/NegativeTrust").getValue(null));
                options.getStringOption("TrustComment").set(configuration.getStringValue("Option/TrustComment").getValue(null));
                options.getBooleanOption("ActivateFcpInterface").set(configuration.getBooleanValue("Option/ActivateFcpInterface").getValue(null));
-               options.getBooleanOption("FcpWriteFromFullAccessOnly").set(configuration.getBooleanValue("Option/FcpWriteFromFullAccessOnly").getValue(null));
+               options.getIntegerOption("FcpFullAccessRequired").set(configuration.getIntValue("Option/FcpFullAccessRequired").getValue(null));
                options.getBooleanOption("SoneRescueMode").set(configuration.getBooleanValue("Option/SoneRescueMode").getValue(null));
 
                /* load known Sones. */
@@ -2122,29 +2123,26 @@ public class Core implements IdentityListener, UpdateListener {
                }
 
                /**
-                * Returns whether write access to the FCP interface is only allowed
-                * from the allowed FCP hosts of the node configuration.
+                * Returns the action level for which full access to the FCP interface
+                * is required.
                 *
-                * @return {@code true} if only allowed hosts are allowed to change data
-                *         using the FCP interface, {@code false} if everybody can
-                *         change data using the FCP interface
+                * @return The action level for which full access to the FCP interface
+                *         is required
                 */
-               public boolean isFcpWriteFromFullAccessOnly() {
-                       return options.getBooleanOption("FcpWriteFromFullAccessOnly").get();
+               public FullAccessRequired getFcpFullAccessRequired() {
+                       return FullAccessRequired.values()[options.getIntegerOption("FcpFullAccessRequired").get()];
                }
 
                /**
-                * Sets whether write access to the FCP interface is only allowed from
-                * the allowed FCP hosts of the node configuration.
+                * Sets the action level for which full access to the FCP interface is
+                * required
                 *
-                * @param fcpWriteFromFullAccessOnly
-                *            {@code true} if only allowed hosts should be allowed to
-                *            change data using the FCP interface, {@code false} if
-                *            everybody can change data using the FCP interface
-                * @return This preferences object
+                * @param fcpFullAccessRequired
+                *            The action level
+                * @return This preferences
                 */
-               public Preferences setFcpWriteFromFullAccessOnly(boolean fcpWriteFromFullAccessOnly) {
-                       options.getBooleanOption("FcpWriteFromFullAccessOnly").set(fcpWriteFromFullAccessOnly);
+               public Preferences setFcpFullAccessRequired(FullAccessRequired fcpFullAccessRequired) {
+                       options.getIntegerOption("FcpFullAccessRequired").set((fcpFullAccessRequired != null) ? fcpFullAccessRequired.ordinal() : null);
                        return this;
                }
 
index e66bb8d..8959b6a 100644 (file)
@@ -29,6 +29,7 @@ import net.pterodactylus.sone.freenet.fcp.Command.ErrorResponse;
 import net.pterodactylus.sone.freenet.fcp.Command.Response;
 import net.pterodactylus.sone.freenet.fcp.FcpException;
 import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.validation.Validation;
 import freenet.pluginmanager.FredPluginFCP;
 import freenet.pluginmanager.PluginNotFoundException;
 import freenet.pluginmanager.PluginReplySender;
@@ -43,14 +44,32 @@ import freenet.support.api.Bucket;
  */
 public class FcpInterface {
 
+       /**
+        * The action level that full access for the FCP connection is required.
+        *
+        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+        */
+       public enum FullAccessRequired {
+
+               /** No action requires full access. */
+               NO,
+
+               /** All writing actions require full access. */
+               WRITING,
+
+               /** All actions require full access. */
+               ALWAYS,
+
+       }
+
        /** The logger. */
        private static final Logger logger = Logging.getLogger(FcpInterface.class);
 
        /** Whether the FCP interface is currently active. */
        private volatile boolean active;
 
-       /** Whether to allow write access from full access hosts only. */
-       private volatile boolean allowWriteFromFullAccessOnly;
+       /** What function full access is required for. */
+       private volatile FullAccessRequired fullAccessRequired = FullAccessRequired.ALWAYS;
 
        /** All available FCP commands. */
        private final Map<String, AbstractSoneCommand> commands = Collections.synchronizedMap(new HashMap<String, AbstractSoneCommand>());
@@ -93,14 +112,14 @@ public class FcpInterface {
        }
 
        /**
-        * Sets whether write access is only allowed from full access hosts.
+        * Sets the action level for which full FCP access is required.
         *
-        * @param allowWriteFromFullAccessOnly
-        *            {@code true} to allow write access only from full access
-        *            hosts, {@code false} to always allow write access
+        * @param fullAccessRequired
+        *            The action level for which full FCP access is required
         */
-       public void setAllowWriteFromFullAccessOnly(boolean allowWriteFromFullAccessOnly) {
-               this.allowWriteFromFullAccessOnly = allowWriteFromFullAccessOnly;
+       public void setFullAccessRequired(FullAccessRequired fullAccessRequired) {
+               Validation.begin().isNotNull("FullAccessRequired", fullAccessRequired).check();
+               this.fullAccessRequired = fullAccessRequired;
        }
 
        //
@@ -131,9 +150,9 @@ public class FcpInterface {
                        return;
                }
                AbstractSoneCommand command = commands.get(parameters.get("Message"));
-               if (allowWriteFromFullAccessOnly && command.requiresWriteAccess() && (accessType == FredPluginFCP.ACCESS_FCP_RESTRICTED)) {
+               if ((accessType == FredPluginFCP.ACCESS_FCP_RESTRICTED) && (((fullAccessRequired == FullAccessRequired.WRITING) && command.requiresWriteAccess()) || (fullAccessRequired == FullAccessRequired.ALWAYS))) {
                        try {
-                               sendReply(pluginReplySender, null, new ErrorResponse(401, "No Write Access"));
+                               sendReply(pluginReplySender, null, new ErrorResponse(401, "Not authorized"));
                        } catch (PluginNotFoundException pnfe1) {
                                logger.log(Level.FINE, "Could not set error to plugin.", pnfe1);
                        }
index 0bad533..161de32 100644 (file)
@@ -19,6 +19,7 @@ package net.pterodactylus.sone.web;
 
 import net.pterodactylus.sone.core.Core.Preferences;
 import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
 import net.pterodactylus.sone.web.page.Page.Request.Method;
 import net.pterodactylus.util.number.Numbers;
 import net.pterodactylus.util.template.Template;
@@ -74,10 +75,11 @@ public class OptionsPage extends SoneTemplatePage {
                                trustComment = null;
                        }
                        preferences.setTrustComment(trustComment);
-                       boolean fcpInterfaceActive = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("fcp-interface-active", 5));
+                       boolean fcpInterfaceActive = request.getHttpRequest().isPartSet("fcp-interface-active");
                        preferences.setFcpInterfaceActive(fcpInterfaceActive);
-                       boolean requireFullAccessHosts = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("require-full-access-hosts", 5));
-                       preferences.setFcpWriteFromFullAccessOnly(requireFullAccessHosts);
+                       Integer fcpFullAccessRequiredInteger = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("fcp-full-access-required", 1), preferences.getFcpFullAccessRequired().ordinal());
+                       FullAccessRequired fcpFullAccessRequired = FullAccessRequired.values()[fcpFullAccessRequiredInteger];
+                       preferences.setFcpFullAccessRequired(fcpFullAccessRequired);
                        boolean soneRescueMode = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("sone-rescue-mode", 5));
                        preferences.setSoneRescueMode(soneRescueMode);
                        boolean clearOnNextRestart = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("clear-on-next-restart", 5));
@@ -96,7 +98,7 @@ public class OptionsPage extends SoneTemplatePage {
                templateContext.set("negative-trust", preferences.getNegativeTrust());
                templateContext.set("trust-comment", preferences.getTrustComment());
                templateContext.set("fcp-interface-active", preferences.isFcpInterfaceActive());
-               templateContext.set("require-full-access-hosts", preferences.isFcpWriteFromFullAccessOnly());
+               templateContext.set("fcp-full-access-required", preferences.getFcpFullAccessRequired().ordinal());
                templateContext.set("sone-rescue-mode", preferences.isSoneRescueMode());
                templateContext.set("clear-on-next-restart", preferences.isClearOnNextRestart());
                templateContext.set("really-clear-on-next-restart", preferences.isReallyClearOnNextRestart());
index b7fbbad..ba38c06 100644 (file)
@@ -43,7 +43,10 @@ Page.Options.Option.NegativeTrust.Description=The amount of trust you want to as
 Page.Options.Option.TrustComment.Description=The comment that will be set in the web of trust for any trust you assign from Sone.
 Page.Options.Section.FcpOptions.Title=FCP Interface Settings
 Page.Options.Option.FcpInterfaceActive.Description=Activate the FCP interface to allow other plugins and remote clients to access your Sone plugin.
-Page.Options.Option.FcpFullAccessRequired.Description=Require FCP connection from allowed hosts (see your {link}node’s configuration, section “FCP”{/link}) to change data using the FCP interface
+Page.Options.Option.FcpFullAccessRequired.Description=Require FCP connection from allowed hosts (see your {link}node’s configuration, section “FCP”{/link})
+Page.Options.Option.FcpFullAccessRequired.Value.No=No
+Page.Options.Option.FcpFullAccessRequired.Value.Writing=For Write Access
+Page.Options.Option.FcpFullAccessRequired.Value.Always=Always
 Page.Options.Section.RescueOptions.Title=Rescue Settings
 Page.Options.Option.SoneRescueMode.Description=Try to rescue your Sones at the next start of the Sone plugin. This will read your all your old Sones from Freenet and ignore any disappearing postings and replies. You have to unlock your local Sones after they have been restored and you have to manually disable the rescue mode once you are satisfied with what has been restored!
 Page.Options.Section.Cleaning.Title=Clean Up
index 74e60ed..dfeb3e9 100644 (file)
 
                <p><input type="checkbox" name="fcp-interface-active"<%if fcp-interface-active> checked="checked"<%/if> /> <%= Page.Options.Option.FcpInterfaceActive.Description|l10n|html></p>
 
-               <p><input type="checkbox" name="require-full-access-hosts"<%if require-full-access-hosts> checked="checked"<%/if> /> <%= Page.Options.Option.FcpFullAccessRequired.Description|l10n|html|replace needle="{link}" replacement='<a href="/config/fcp">'|replace needle="{/link}" replacement='</a>'></p>
+               <p>
+                       <%= Page.Options.Option.FcpFullAccessRequired.Description|l10n|html|replace needle="{link}" replacement='<a href="/config/fcp">'|replace needle="{/link}" replacement='</a>'>
+                       <select name="fcp-full-access-required">
+                               <option value="0"<%if fcp-full-access-required|match value="0"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.No|l10n|html></option>
+                               <option value="1"<%if fcp-full-access-required|match value="1"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.Writing|l10n|html></option>
+                               <option value="2"<%if fcp-full-access-required|match value="2"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.Always|l10n|html></option>
+                       </select>
+               </p>
 
                <h2><%= Page.Options.Section.RescueOptions.Title|l10n|html></h2>