Author: toad
Date: 2008-09-03 12:31:58 +0000 (Wed, 03 Sep 2008)
New Revision: 22363

Modified:
   trunk/freenet/src/freenet/clients/http/ConfigToadlet.java
   trunk/freenet/src/freenet/clients/http/PageMaker.java
   trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
   trunk/freenet/src/freenet/node/SecurityLevels.java
Log:
Changing the network security level works, and warns the user and gets 
confirmation when they're going to do something stupid.


Modified: trunk/freenet/src/freenet/clients/http/ConfigToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/ConfigToadlet.java   2008-09-02 
22:43:59 UTC (rev 22362)
+++ trunk/freenet/src/freenet/clients/http/ConfigToadlet.java   2008-09-03 
12:31:58 UTC (rev 22363)
@@ -20,6 +20,7 @@
 import freenet.l10n.L10n;
 import freenet.node.Node;
 import freenet.node.NodeClientCore;
+import freenet.node.SecurityLevels;
 import freenet.node.SecurityLevels.NETWORK_THREAT_LEVEL;
 import freenet.node.useralerts.AbstractUserAlert;
 import freenet.node.useralerts.UserAlert;
@@ -105,9 +106,6 @@

        @Override
     public void handlePost(URI uri, HTTPRequest request, ToadletContext ctx) 
throws ToadletContextClosedException, IOException {
-               StringBuffer errbuf = new StringBuffer();
-               SubConfig[] sc = config.getConfigs();
-               
                String pass = request.getPartAsString("formPassword", 32);
                if((pass == null) || !pass.equals(core.formPassword)) {
                        MultiValueTable headers = new MultiValueTable();
@@ -116,6 +114,64 @@
                        return;
                }

+               if(request.isPartSet("seclevels")) {
+                       // Handle the security level changes.
+                       
+                       HTMLNode pageNode = null;
+                       HTMLNode content = null;
+                       HTMLNode ul = null;
+                       HTMLNode formNode = null;
+                       boolean addedWarning = false;
+                       String configName = 
"security-levels.networkThreatLevel";
+                       String confirm = 
"security-levels.networkThreatLevel.confirm";
+                       String networkThreatLevel = 
request.getPartAsString(configName, 128);
+                       NETWORK_THREAT_LEVEL newThreatLevel = 
SecurityLevels.parseNetworkThreatLevel(networkThreatLevel);
+                       if(newThreatLevel != null) {
+                               if(newThreatLevel != 
node.securityLevels.getNetworkThreatLevel()) {
+                                       if(!request.isPartSet(confirm)) {
+                                               HTMLNode warning = 
node.securityLevels.getConfirmWarning(newThreatLevel, confirm);
+                                               if(warning != null) {
+                                                       if(pageNode == null) {
+                                                               pageNode = 
ctx.getPageMaker().getPageNode(L10n.getString("ConfigToadlet.fullTitle", new 
String[] { "name" }, new String[] { node.getMyName() }), ctx);
+                                                               content = 
ctx.getPageMaker().getContentNode(pageNode);
+                                                               formNode = 
ctx.addFormChild(content, ".", "configFormSecLevels");
+                                                               ul = 
formNode.addChild("ul", "class", "config");
+                                                       }
+                                                       HTMLNode seclevelGroup 
= ul.addChild("li");
+
+                                                       
seclevelGroup.addChild("input", new String[] { "type", "name", "value" }, new 
String[] { "hidden", configName, networkThreatLevel });
+                                                       HTMLNode infobox = 
seclevelGroup.addChild("div", "class", "infobox infobox-information");
+                                                       infobox.addChild("div", 
"class", "infobox-header", l10nSec("networkThreatLevelConfirmTitle", "mode", 
SecurityLevels.localisedName(newThreatLevel)));
+                                                       HTMLNode infoboxContent 
= infobox.addChild("div", "class", "infobox-content");
+                                                       
infoboxContent.addChild(warning);
+                                                       addedWarning = true;
+                                               } else {
+                                                       // Apply immediately, 
no confirm needed.
+                                                       
node.securityLevels.setThreatLevel(newThreatLevel);
+                                               }
+                                       } else {
+                                               // Apply immediately, user 
confirmed it.
+                                               
node.securityLevels.setThreatLevel(newThreatLevel);
+                                       }
+                               }
+                       }
+                       if(pageNode != null) {
+                               formNode.addChild("input", new String[] { 
"type", "name", "value" }, new String[] { "hidden", "seclevels", "on" });
+                               formNode.addChild("input", new String[] { 
"type", "value" }, new String[] { "submit", l10n("apply")});
+                               formNode.addChild("input", new String[] { 
"type", "value" }, new String[] { "reset",  l10n("reset")});
+                               writeHTMLReply(ctx, 200, "OK", 
pageNode.generate());
+                               return;
+                       } else {
+                               MultiValueTable headers = new MultiValueTable();
+                               headers.put("Location", 
"/config/?mode="+MODE_SECURITY_LEVELS);
+                               ctx.sendReplyHeaders(302, "Found", headers, 
null, 0);
+                               return;
+                       }
+               }
+               
+               SubConfig[] sc = config.getConfigs();
+               StringBuffer errbuf = new StringBuffer();
+               
                if(!ctx.isAllowedFullAccess()) {
                        super.sendErrorPage(ctx, 403, 
L10n.getString("Toadlet.unauthorizedTitle"), 
L10n.getString("Toadlet.unauthorized"));
                        return;
@@ -352,9 +408,9 @@
                for(NETWORK_THREAT_LEVEL level : NETWORK_THREAT_LEVEL.values()) 
{
                        HTMLNode input;
                        if(level == networkLevel) {
-                               input = 
seclevelGroup.addChild("p").addChild("input", new String[] { "type", "checked", 
"name" }, new String[] { "radio", "on", controlName });
+                               input = 
seclevelGroup.addChild("p").addChild("input", new String[] { "type", "checked", 
"name", "value" }, new String[] { "radio", "on", controlName, level.name() });
                        } else {
-                               input = 
seclevelGroup.addChild("p").addChild("input", new String[] { "type", "name" }, 
new String[] { "radio", controlName });
+                               input = 
seclevelGroup.addChild("p").addChild("input", new String[] { "type", "name", 
"value" }, new String[] { "radio", controlName, level.name() });
                        }
                        input.addChild("b", 
l10nSec("networkThreatLevel.name."+level));
                        input.addChild("#", ": ");
@@ -362,6 +418,7 @@
                }
                // FIXME implement the rest, it should be very similar to the 
above.

+               formNode.addChild("input", new String[] { "type", "name", 
"value" }, new String[] { "hidden", "seclevels", "on" });
                formNode.addChild("input", new String[] { "type", "value" }, 
new String[] { "submit", l10n("apply")});
                formNode.addChild("input", new String[] { "type", "value" }, 
new String[] { "reset",  l10n("reset")});
        }
@@ -370,8 +427,11 @@
        private String l10nSec(String key) {
                return L10n.getString("SecurityLevels."+key);
        }
+       
+       private String l10nSec(String key, String pattern, String value) {
+               return L10n.getString("SecurityLevels."+key, pattern, value);
+       }

-
        @Override
     public String supportedMethods() {
                return "GET, POST";

Modified: trunk/freenet/src/freenet/clients/http/PageMaker.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/PageMaker.java       2008-09-02 
22:43:59 UTC (rev 22362)
+++ trunk/freenet/src/freenet/clients/http/PageMaker.java       2008-09-03 
12:31:58 UTC (rev 22363)
@@ -272,6 +272,14 @@
                HTMLNode row = table.addChild("tr");
                HTMLNode cell = row.addChild("td");

+               if(alternateMode > -1) {
+                       if(mode != alternateMode)
+                               cell.addChild("a", new String[] { "href", 
"title" }, new String[] { "?mode="+alternateMode, 
L10n.getString(alternateModeTooltipKey) }, 
L10n.getString(alternateModeTitleKey));
+                       else
+                               cell.addChild("b", "title", 
L10n.getString(alternateModeTooltipKey), L10n.getString(alternateModeTitleKey));
+                       cell = row.addChild("td");
+               }
+               
                if(mode != MODE_SIMPLE)
                        cell.addChild("a", new String[] { "href", "title" }, 
new String[] { "?mode=1", l10n("modeSimpleTooltip") }, l10n("modeSimple"));
                else
@@ -281,14 +289,6 @@
                        cell.addChild("a", new String[] { "href", "title" }, 
new String[] { "?mode=2", l10n("modeAdvancedTooltip") }, l10n("modeAdvanced"));
                else
                        cell.addChild("b", "title", 
l10n("modeAdvancedTooltip"), l10n("modeAdvanced"));
-               if(alternateMode > -1) {
-                       cell = row.addChild("td");
-                       if(mode != alternateMode)
-                               cell.addChild("a", new String[] { "href", 
"title" }, new String[] { "?mode="+alternateMode, 
L10n.getString(alternateModeTooltipKey) }, 
L10n.getString(alternateModeTitleKey));
-                       else
-                               cell.addChild("b", "title", 
L10n.getString(alternateModeTooltipKey), L10n.getString(alternateModeTitleKey));
-               }
-               
                return mode;
        }


Modified: trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties
===================================================================
--- trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties   2008-09-02 
22:43:59 UTC (rev 22362)
+++ trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties   2008-09-03 
12:31:58 UTC (rev 22363)
@@ -1049,6 +1049,15 @@
 SecurityLevels.networkThreatLevel.desc.HIGH=I intend to access information 
that could get me arrested, imprisoned, or worse.  I am worried about my 
government or ISP blocking Freenet. I understand that Freenet is experimental 
and ${bold}cannot${/bold} ensure security against certain known attacks, but I 
accept the risks compared to the alternatives.  Freenet will not connect to 
unknown nodes, so ${bold}I must have friends already using Freenet to select 
this mode${/bold}.
 SecurityLevels.networkThreatLevel.desc.NORMAL=I live in a relatively free 
country, but I would like to make it more difficult for others to monitor my 
communications.  Freenet will be reasonably careful to protect your anonymity, 
at some performance cost. Freenet will automatically connect to unknown nodes.  
We recommend that you add friends running Freenet and upgrade to HIGH.
 SecurityLevels.networkThreatLevel.desc.LOW=I do not care about monitoring and 
want maximum performance.  It may be quite easy for others to discover my 
identity.
+SecurityLevels.noFriendsWarning=You have not added any Friends. If you set the 
network security level to high, you will be unable to connect to Freenet until 
you have at least one connected Friend! Note that for there to be any 
meaningful security benefit, these must be people you actually know and at 
least marginally trust, and for good performance you will need at least 5-10 of 
them connected at any time. Are you sure?
+SecurityLevels.noFriendsCheckbox=I am sure, enable high network security 
level, I will add some Friends ASAP.
+SecurityLevels.noConnectedFriendsWarning=You do not have any connected 
Friends, although you have added ${added} friends. If you set the network 
security level to high, you will only be able to connect to Freenet when your 
friends are online, which they are not at the moment. You should add additional 
Friends, only use Freenet when your friends are connected, or not upgrade to 
high security. Note that for there to be any meaningful security benefit, your 
Friends must be people you actually know and at least marginally trust, and for 
good performance you will need at least 5-10 of them connected at any time. Are 
you sure?
+SecurityLevels.noConnectedFriendsCheckbox=I am sure, I will add more Friends 
and/or I accept that Freenet will only be online when my existing Friends are 
online.
+SecurityLevels.fewConnectedFriendsWarning=You only have ${connected} connected 
Friends right now, and you have added ${added} friends in total. If you set the 
network security level to high, Freenet will only connect to your Friends, so 
your performance may be significantly reduced, and if all your Friends are 
offline then it will not be able to connect at all. Note that Friends must be 
people you know and at least marginally trust for there to be any real security 
benefit, and you will need at least 5-10 connected Friends for good 
performance. Are you sure?
+SecurityLevels.fewConnectedFriendsCheckbox=I am sure, I will add more Friends 
and/or I accept the performance cost and the fact that Freenet may not connect 
when my Friends are offline.
+SecurityLevels.networkThreatLevelLowWarning=You are about to downgrade your 
node's network security level to low. This means that it will be easy for 
strangers to attack your anonymity over the Internet. Are you sure?
+SecurityLevels.networkThreatLevelLowCheckbox=I am sure, I want more speed and 
I don't care who can tell what I'm doing with Freenet!
+SecurityLevels.networkThreatLevelConfirmTitle=WARNING: Setting network 
security level to ${mode}
 ShortOption.parseError=Cannot parse value as a string array: ${error}
 ShortOption.parseError=The value specified can't be parsed as a 16-bit integer 
: ${val}
 SimpleToadletServer.advancedMode=Enable Advanced Mode?

Modified: trunk/freenet/src/freenet/node/SecurityLevels.java
===================================================================
--- trunk/freenet/src/freenet/node/SecurityLevels.java  2008-09-02 22:43:59 UTC 
(rev 22362)
+++ trunk/freenet/src/freenet/node/SecurityLevels.java  2008-09-03 12:31:58 UTC 
(rev 22363)
@@ -11,6 +11,8 @@
 import freenet.config.NodeNeedRestartException;
 import freenet.config.PersistentConfig;
 import freenet.config.SubConfig;
+import freenet.l10n.L10n;
+import freenet.support.HTMLNode;
 import freenet.support.Logger;
 import freenet.support.api.StringCallback;

@@ -27,6 +29,8 @@
  */
 public class SecurityLevels {

+       private final Node node;
+       
        public enum NETWORK_THREAT_LEVEL {
                HIGH, // paranoid, darknet only
                NORMAL, // normal setting, darknet/opennet hybrid
@@ -53,13 +57,16 @@
        private MyCallback<PHYSICAL_THREAT_LEVEL> physicalThreatLevelCallback;

        public SecurityLevels(Node node, PersistentConfig config) {
+               this.node = node;
                SubConfig myConfig = new SubConfig("security-levels", config);
                int sortOrder = 0;
                networkThreatLevelCallback = new 
MyCallback<NETWORK_THREAT_LEVEL>() {

                        @Override
                        public String get() {
-                               return networkThreatLevel.name();
+                               synchronized(SecurityLevels.this) {
+                                       return networkThreatLevel.name();
+                               }
                        }

                        public String[] getPossibleValues() {
@@ -77,9 +84,12 @@

                        @Override
                        protected void setValue(String val) throws 
InvalidConfigValueException {
-                               NETWORK_THREAT_LEVEL newValue = 
NETWORK_THREAT_LEVEL.valueOf(val);
+                               NETWORK_THREAT_LEVEL newValue = 
parseNetworkThreatLevel(val);
                                if(newValue != null)
                                        throw new 
InvalidConfigValueException("Invalid value for network threat level: "+val);
+                               synchronized(SecurityLevels.this) {
+                                       networkThreatLevel = newValue;
+                               }
                        }

                };
@@ -89,7 +99,9 @@

                        @Override
                        public String get() {
-                               return friendsThreatLevel.name();
+                               synchronized(SecurityLevels.this) {
+                                       return friendsThreatLevel.name();
+                               }
                        }

                        public String[] getPossibleValues() {
@@ -110,6 +122,9 @@
                                FRIENDS_THREAT_LEVEL newValue = 
FRIENDS_THREAT_LEVEL.valueOf(val);
                                if(newValue != null)
                                        throw new 
InvalidConfigValueException("Invalid value for friends threat level: "+val);
+                               synchronized(SecurityLevels.this) {
+                                       friendsThreatLevel = newValue;
+                               }
                        }

                };
@@ -119,7 +134,9 @@

                        @Override
                        public String get() {
-                               return physicalThreatLevel.name();
+                               synchronized(SecurityLevels.this) {
+                                       return physicalThreatLevel.name();
+                               }
                        }

                        public String[] getPossibleValues() {
@@ -140,22 +157,26 @@
                                PHYSICAL_THREAT_LEVEL newValue = 
PHYSICAL_THREAT_LEVEL.valueOf(val);
                                if(newValue != null)
                                        throw new 
InvalidConfigValueException("Invalid value for physical threat level: "+val);
+                               synchronized(SecurityLevels.this) {
+                                       physicalThreatLevel = newValue;
+                               }
                        }

                };
                myConfig.register("physicalThreatLevel", "NORMAL", sortOrder++, 
false, true, "SecurityLevels.physicalThreatLevelShort", 
"SecurityLevels.physicalThreatLevel", physicalThreatLevelCallback);
                physicalThreatLevel = 
PHYSICAL_THREAT_LEVEL.valueOf(myConfig.getString("physicalThreatLevel"));
+               myConfig.finishedInitialization();
        }

-       public void 
addNetworkThreatLevelListener(SecurityLevelListener<NETWORK_THREAT_LEVEL> 
listener) {
+       public synchronized void 
addNetworkThreatLevelListener(SecurityLevelListener<NETWORK_THREAT_LEVEL> 
listener) {
                networkThreatLevelCallback.addListener(listener);
        }

-       public void 
addFriendsThreatLevelListener(SecurityLevelListener<FRIENDS_THREAT_LEVEL> 
listener) {
+       public synchronized void 
addFriendsThreatLevelListener(SecurityLevelListener<FRIENDS_THREAT_LEVEL> 
listener) {
                friendsThreatLevelCallback.addListener(listener);
        }

-       public void 
addPhysicalThreatLevelListener(SecurityLevelListener<PHYSICAL_THREAT_LEVEL> 
listener) {
+       public synchronized void 
addPhysicalThreatLevelListener(SecurityLevelListener<PHYSICAL_THREAT_LEVEL> 
listener) {
                physicalThreatLevelCallback.addListener(listener);
        }

@@ -194,5 +215,67 @@
        public NETWORK_THREAT_LEVEL getNetworkThreatLevel() {
                return networkThreatLevel;
        }
+
+       public static NETWORK_THREAT_LEVEL parseNetworkThreatLevel(String arg) {
+               try {
+                       return NETWORK_THREAT_LEVEL.valueOf(arg);
+               } catch (IllegalArgumentException e) {
+                       return null;
+               }
+       }
+
+       /**
+        * If changing to the new threat level is a potential problem, warn the 
user,
+        * and include a checkbox for confirmation.
+        * @param newThreatLevel
+        * @return
+        */
+       public HTMLNode getConfirmWarning(NETWORK_THREAT_LEVEL newThreatLevel, 
String checkboxName) {
+               if(newThreatLevel == networkThreatLevel)
+                       return null; // Not going to be changed.
+               HTMLNode parent = new HTMLNode("div");
+               if(newThreatLevel == NETWORK_THREAT_LEVEL.HIGH) {
+                       if(node.peers.getDarknetPeers().length == 0) {
+                               parent.addChild("p", l10n("noFriendsWarning"));
+                               parent.addChild("input", new String[] { "type", 
"name", "value" }, new String[] { "checkbox", checkboxName, "off" }, 
l10n("noFriendsCheckbox"));
+                       } else if(node.peers.countConnectedDarknetPeers() == 0) 
{
+                               parent.addChild("p", 
l10n("noConnectedFriendsWarning", "added", 
Integer.toString(node.peers.getDarknetPeers().length)));
+                               parent.addChild("input", new String[] { "type", 
"name", "value" }, new String[] { "checkbox", checkboxName, "off" }, 
l10n("noConnectedFriendsCheckbox"));
+                       } else if(node.peers.countConnectedDarknetPeers() < 10) 
{
+                               parent.addChild("p", 
l10n("fewConnectedFriendsWarning", new String[] { "connected", "added" }, new 
String[] { Integer.toString(node.peers.countConnectedDarknetPeers()), 
Integer.toString(node.peers.getDarknetPeers().length)}));
+                               parent.addChild("input", new String[] { "type", 
"name", "value" }, new String[] { "checkbox", checkboxName, "off" }, 
l10n("fewConnectedFriendsCheckbox"));
+                       } else return null;
+                       return parent;
+               } else if(newThreatLevel == NETWORK_THREAT_LEVEL.LOW) {
+                       parent.addChild("p", 
l10n("networkThreatLevelLowWarning"));
+                       parent.addChild("input", new String[] { "type", "name", 
"value" }, new String[] { "checkbox", checkboxName, "off" }, 
l10n("networkThreatLevelLowCheckbox"));
+                       return parent;
+               } // Don't warn on switching to NORMAL.
+               return null;
+       }
+
+       private String l10n(String string) {
+               return L10n.getString("SecurityLevels."+string);
+       }
+
+       private String l10n(String string, String pattern, String value) {
+               return L10n.getString("SecurityLevels."+string, pattern, value);
+       }
+
+       private String l10n(String string, String[] patterns, String[] values) {
+               return L10n.getString("SecurityLevels."+string, patterns, 
values);
+       }
+
+       public void setThreatLevel(NETWORK_THREAT_LEVEL newThreatLevel) {
+               if(newThreatLevel == null) throw new NullPointerException();
+               synchronized(this) {
+                       networkThreatLevel = newThreatLevel;
+               }
+               node.config.store();
+       }
+
+       public static String localisedName(NETWORK_THREAT_LEVEL newThreatLevel) 
{
+               return 
L10n.getString("SecurityLevels.networkThreatLevel.name."+newThreatLevel.name());
+       }

 }


Reply via email to