Author: toad
Date: 2008-09-02 22:43:59 +0000 (Tue, 02 Sep 2008)
New Revision: 22362
Added:
trunk/freenet/src/freenet/node/SecurityLevelListener.java
trunk/freenet/src/freenet/node/SecurityLevels.java
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/Node.java
Log:
Beginnings of security level support.
Cannot yet change the seclevel, and it doesn't change anything yet.
Modified: trunk/freenet/src/freenet/clients/http/ConfigToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/ConfigToadlet.java 2008-09-02
20:27:10 UTC (rev 22361)
+++ trunk/freenet/src/freenet/clients/http/ConfigToadlet.java 2008-09-02
22:43:59 UTC (rev 22362)
@@ -20,6 +20,7 @@
import freenet.l10n.L10n;
import freenet.node.Node;
import freenet.node.NodeClientCore;
+import freenet.node.SecurityLevels.NETWORK_THREAT_LEVEL;
import freenet.node.useralerts.AbstractUserAlert;
import freenet.node.useralerts.UserAlert;
import freenet.support.HTMLNode;
@@ -215,6 +216,8 @@
return L10n.getString("ConfigToadlet." + string);
}
+ public static final int MODE_SECURITY_LEVELS = 3;
+
@Override
public void handleGet(URI uri, HTTPRequest req, ToadletContext ctx) throws
ToadletContextClosedException, IOException {
@@ -231,8 +234,12 @@
contentNode.addChild(core.alerts.createSummary());
- final int mode =
ctx.getPageMaker().drawModeSelectionArray(core, req, contentNode);
+ final int mode =
ctx.getPageMaker().drawModeSelectionArray(core, req, contentNode,
MODE_SECURITY_LEVELS, "SecurityLevels.title", "SecurityLevels.tooltip");
+ if(mode == MODE_SECURITY_LEVELS) {
+ drawSecurityLevelsPage(contentNode, ctx);
+ } else {
+
if(mode >= PageMaker.MODE_ADVANCED){
HTMLNode navigationBar =
ctx.getPageMaker().getInfobox("navbar", l10n("configNavTitle"));
HTMLNode navigationContent =
ctx.getPageMaker().getContentNode(navigationBar).addChild("ul");
@@ -243,6 +250,7 @@
HTMLNode nextTableCell = navigationTableRow;
for(int i=0; i<sc.length;i++){
+ if(sc[i].getPrefix().equals("security-levels"))
continue;
nextTableCell.addChild("td", "class",
"config_navigation").addChild("li").addChild("a", "href", '#'
+sc[i].getPrefix(), l10n(sc[i].getPrefix()));
}
contentNode.addChild(navigationBar);
@@ -271,6 +279,7 @@
for(int i=0; i<sc.length;i++){
short displayedConfigElements = 0;
+ if(sc[i].getPrefix().equals("security-levels"))
continue;
Option<?>[] o = sc[i].getOptions();
HTMLNode configGroupUlNode = new HTMLNode("ul",
"class", "config");
@@ -321,9 +330,48 @@
formNode.addChild("input", new String[] { "type", "value" },
new String[] { "submit", l10n("apply")});
formNode.addChild("input", new String[] { "type", "value" },
new String[] { "reset", l10n("reset")});
+ }
+
this.writeHTMLReply(ctx, 200, "OK", pageNode.generate());
}
+ private void drawSecurityLevelsPage(HTMLNode contentNode,
ToadletContext ctx) {
+ HTMLNode infobox = contentNode.addChild("div", "class",
"infobox infobox-normal");
+ infobox.addChild("div", "class", "infobox-header",
l10nSec("title"));
+ HTMLNode configNode = infobox.addChild("div", "class",
"infobox-content");
+ HTMLNode formNode = ctx.addFormChild(configNode, ".",
"configFormSecLevels");
+ // Network security level
+ formNode.addChild("div", "class", "configprefix",
l10nSec("networkThreatLevelShort"));
+ HTMLNode ul = formNode.addChild("ul", "class", "config");
+ HTMLNode seclevelGroup = ul.addChild("li");
+ seclevelGroup.addChild("#", l10nSec("networkThreatLevel"));
+
+ NETWORK_THREAT_LEVEL networkLevel =
node.securityLevels.getNetworkThreatLevel();
+
+ String controlName = "security-levels.networkThreatLevel";
+ 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 });
+ } else {
+ input =
seclevelGroup.addChild("p").addChild("input", new String[] { "type", "name" },
new String[] { "radio", controlName });
+ }
+ input.addChild("b",
l10nSec("networkThreatLevel.name."+level));
+ input.addChild("#", ": ");
+ L10n.addL10nSubstitution(input,
"SecurityLevels.networkThreatLevel.desc."+level, new String[] { "bold", "/bold"
}, new String[] { "<b>", "</b>" });
+ }
+ // FIXME implement the rest, it should be very similar to the
above.
+
+ formNode.addChild("input", new String[] { "type", "value" },
new String[] { "submit", l10n("apply")});
+ formNode.addChild("input", new String[] { "type", "value" },
new String[] { "reset", l10n("reset")});
+ }
+
+
+ private String l10nSec(String key) {
+ return L10n.getString("SecurityLevels."+key);
+ }
+
+
@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
20:27:10 UTC (rev 22361)
+++ trunk/freenet/src/freenet/clients/http/PageMaker.java 2008-09-02
22:43:59 UTC (rev 22362)
@@ -255,6 +255,10 @@
}
protected int drawModeSelectionArray(NodeClientCore core, HTTPRequest
req, HTMLNode contentNode) {
+ return drawModeSelectionArray(core, req, contentNode, -1, null,
null);
+ }
+
+ protected int drawModeSelectionArray(NodeClientCore core, HTTPRequest
req, HTMLNode contentNode, int alternateMode, String alternateModeTitleKey,
String alternateModeTooltipKey) {
// Mode can be changed by a link, not just by the default
int mode = core.isAdvancedModeEnabled() ? MODE_ADVANCED :
MODE_SIMPLE;
@@ -277,6 +281,13 @@
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
20:27:10 UTC (rev 22361)
+++ trunk/freenet/src/freenet/l10n/freenet.l10n.en.properties 2008-09-02
22:43:59 UTC (rev 22362)
@@ -1039,6 +1039,16 @@
RequestStarterGroup.schedulerLong=Set the priority policy scheme used by the
scheduler.
RevocationKeyFoundUserAlert.text=Your node has found the auto-updater's
revocation key on the network. It means that our auto-updating system is likely
to have been COMPROMIZED! Consequently, it has been disabled on your node to
prevent "bad things" to be installed. We strongly advise you to check the
project's website for updates. Please take care of verifying that the website
hasn't been spoofed either. The revocation message is the following :
${message}.
RevocationKeyFoundUserAlert.title=The private key of the project has been
compromized!
+SecurityLevels.title=Security levels
+SecurityLevels.tooltip=Configure the node's degree of security
+SecurityLevels.networkThreatLevelShort=Protection against a stranger attacking
you over the Internet
+SecurityLevels.networkThreatLevel=How much security do you need against
Internet providers, corporations, governments, bored kids etc attempting to
monitor your use of Freenet?
+SecurityLevels.networkThreatLevel.name.HIGH=HIGH
+SecurityLevels.networkThreatLevel.name.NORMAL=NORMAL
+SecurityLevels.networkThreatLevel.name.LOW=LOW
+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.
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/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2008-09-02 20:27:10 UTC (rev
22361)
+++ trunk/freenet/src/freenet/node/Node.java 2008-09-02 22:43:59 UTC (rev
22362)
@@ -471,6 +471,8 @@
/** NodeUpdater **/
public final NodeUpdateManager nodeUpdater;
+ public final SecurityLevels securityLevels;
+
// Things that's needed to keep track of
public final PluginManager pluginManager;
@@ -753,6 +755,8 @@
runningCHKOfferReplyUIDs = new HashSet();
runningSSKOfferReplyUIDs = new HashSet();
+ this.securityLevels = new SecurityLevels(this, config);
+
// Directory for node-related files other than store
nodeConfig.register("nodeDir", ".", sortOrder++, true, true /*
because can't be changed on the fly, also for packages */, "Node.nodeDir",
"Node.nodeDirLong",
Added: trunk/freenet/src/freenet/node/SecurityLevelListener.java
===================================================================
--- trunk/freenet/src/freenet/node/SecurityLevelListener.java
(rev 0)
+++ trunk/freenet/src/freenet/node/SecurityLevelListener.java 2008-09-02
22:43:59 UTC (rev 22362)
@@ -0,0 +1,7 @@
+package freenet.node;
+
+public interface SecurityLevelListener<T> {
+
+ public void onChange(T oldLevel, T newLevel);
+
+}
Added: trunk/freenet/src/freenet/node/SecurityLevels.java
===================================================================
--- trunk/freenet/src/freenet/node/SecurityLevels.java
(rev 0)
+++ trunk/freenet/src/freenet/node/SecurityLevels.java 2008-09-02 22:43:59 UTC
(rev 22362)
@@ -0,0 +1,198 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.node;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import freenet.config.EnumerableOptionCallback;
+import freenet.config.InvalidConfigValueException;
+import freenet.config.NodeNeedRestartException;
+import freenet.config.PersistentConfig;
+import freenet.config.SubConfig;
+import freenet.support.Logger;
+import freenet.support.api.StringCallback;
+
+/**
+ * We have 3 basic security settings. The user chooses these in the first-time
+ * wizard, and can reconfigure them at any time. Each impacts on many other
+ * config settings, changing their defaults and changing their values when the
+ * security level changes, but the user can change those options independantly
if
+ * they do not change the security level. These options are important, and
there
+ * are explanations of every option for each setting. They have their own
+ * sub-page on the config toadlet. And the security levels are displayed on the
+ * homepage as a useralert (instead of the opennet warning).
+ * @author Matthew Toseland <toad at amphibian.dyndns.org> (0xE43DA450)
+ */
+public class SecurityLevels {
+
+ public enum NETWORK_THREAT_LEVEL {
+ HIGH, // paranoid, darknet only
+ NORMAL, // normal setting, darknet/opennet hybrid
+ LOW // turn off every performance impacting security measure
+ }
+
+ public enum FRIENDS_THREAT_LEVEL {
+ HIGH, // Share no/minimal information and take measures to
reduce harm if Friends are compromized
+ NORMAL, // Share some information
+ LOW // Friends are ultimately trusted
+ }
+
+ public enum PHYSICAL_THREAT_LEVEL {
+ NORMAL, // Encrypt temp files etc etc
+ LOW // Don't encrypt temp files etc etc
+ }
+
+ NETWORK_THREAT_LEVEL networkThreatLevel;
+ FRIENDS_THREAT_LEVEL friendsThreatLevel;
+ PHYSICAL_THREAT_LEVEL physicalThreatLevel;
+
+ private MyCallback<NETWORK_THREAT_LEVEL> networkThreatLevelCallback;
+ private MyCallback<FRIENDS_THREAT_LEVEL> friendsThreatLevelCallback;
+ private MyCallback<PHYSICAL_THREAT_LEVEL> physicalThreatLevelCallback;
+
+ public SecurityLevels(Node node, PersistentConfig config) {
+ SubConfig myConfig = new SubConfig("security-levels", config);
+ int sortOrder = 0;
+ networkThreatLevelCallback = new
MyCallback<NETWORK_THREAT_LEVEL>() {
+
+ @Override
+ public String get() {
+ return networkThreatLevel.name();
+ }
+
+ public String[] getPossibleValues() {
+ NETWORK_THREAT_LEVEL[] values =
NETWORK_THREAT_LEVEL.values();
+ String[] names = new String[values.length];
+ for(int i=0;i<names.length;i++)
+ names[i] = values[i].name();
+ return names;
+ }
+
+ @Override
+ protected NETWORK_THREAT_LEVEL getValue() {
+ return networkThreatLevel;
+ }
+
+ @Override
+ protected void setValue(String val) throws
InvalidConfigValueException {
+ NETWORK_THREAT_LEVEL newValue =
NETWORK_THREAT_LEVEL.valueOf(val);
+ if(newValue != null)
+ throw new
InvalidConfigValueException("Invalid value for network threat level: "+val);
+ }
+
+ };
+ myConfig.register("networkThreatLevel", "NORMAL", sortOrder++,
false, true, "SecurityLevels.networkThreatLevelShort",
"SecurityLevels.networkThreatLevel", networkThreatLevelCallback);
+ networkThreatLevel =
NETWORK_THREAT_LEVEL.valueOf(myConfig.getString("networkThreatLevel"));
+ friendsThreatLevelCallback = new
MyCallback<FRIENDS_THREAT_LEVEL>() {
+
+ @Override
+ public String get() {
+ return friendsThreatLevel.name();
+ }
+
+ public String[] getPossibleValues() {
+ FRIENDS_THREAT_LEVEL[] values =
FRIENDS_THREAT_LEVEL.values();
+ String[] names = new String[values.length];
+ for(int i=0;i<names.length;i++)
+ names[i] = values[i].name();
+ return names;
+ }
+
+ @Override
+ protected FRIENDS_THREAT_LEVEL getValue() {
+ return friendsThreatLevel;
+ }
+
+ @Override
+ protected void setValue(String val) throws
InvalidConfigValueException {
+ FRIENDS_THREAT_LEVEL newValue =
FRIENDS_THREAT_LEVEL.valueOf(val);
+ if(newValue != null)
+ throw new
InvalidConfigValueException("Invalid value for friends threat level: "+val);
+ }
+
+ };
+ myConfig.register("friendsThreatLevel", "NORMAL", sortOrder++,
false, true, "SecurityLevels.friendsThreatLevelShort",
"SecurityLevels.friendsThreatLevel", friendsThreatLevelCallback);
+ friendsThreatLevel =
FRIENDS_THREAT_LEVEL.valueOf(myConfig.getString("friendsThreatLevel"));
+ physicalThreatLevelCallback = new
MyCallback<PHYSICAL_THREAT_LEVEL>() {
+
+ @Override
+ public String get() {
+ return physicalThreatLevel.name();
+ }
+
+ public String[] getPossibleValues() {
+ PHYSICAL_THREAT_LEVEL[] values =
PHYSICAL_THREAT_LEVEL.values();
+ String[] names = new String[values.length];
+ for(int i=0;i<names.length;i++)
+ names[i] = values[i].name();
+ return names;
+ }
+
+ @Override
+ protected PHYSICAL_THREAT_LEVEL getValue() {
+ return physicalThreatLevel;
+ }
+
+ @Override
+ protected void setValue(String val) throws
InvalidConfigValueException {
+ PHYSICAL_THREAT_LEVEL newValue =
PHYSICAL_THREAT_LEVEL.valueOf(val);
+ if(newValue != null)
+ throw new
InvalidConfigValueException("Invalid value for physical threat level: "+val);
+ }
+
+ };
+ myConfig.register("physicalThreatLevel", "NORMAL", sortOrder++,
false, true, "SecurityLevels.physicalThreatLevelShort",
"SecurityLevels.physicalThreatLevel", physicalThreatLevelCallback);
+ physicalThreatLevel =
PHYSICAL_THREAT_LEVEL.valueOf(myConfig.getString("physicalThreatLevel"));
+ }
+
+ public void
addNetworkThreatLevelListener(SecurityLevelListener<NETWORK_THREAT_LEVEL>
listener) {
+ networkThreatLevelCallback.addListener(listener);
+ }
+
+ public void
addFriendsThreatLevelListener(SecurityLevelListener<FRIENDS_THREAT_LEVEL>
listener) {
+ friendsThreatLevelCallback.addListener(listener);
+ }
+
+ public void
addPhysicalThreatLevelListener(SecurityLevelListener<PHYSICAL_THREAT_LEVEL>
listener) {
+ physicalThreatLevelCallback.addListener(listener);
+ }
+
+ private abstract class MyCallback<T> extends StringCallback implements
EnumerableOptionCallback {
+
+ private ArrayList<SecurityLevelListener<T>> listeners;
+
+ public void addListener(SecurityLevelListener<T> listener) {
+ if(listeners.contains(listener)) {
+ Logger.error(this, "Already have listener
"+listener+" in "+this);
+ return;
+ }
+ listeners.add(listener);
+ }
+
+ public void setPossibleValues(String[] val) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void set(String val) throws InvalidConfigValueException,
NodeNeedRestartException {
+ T oldLevel = getValue();
+ setValue(val);
+ T newLevel = getValue();
+ for(SecurityLevelListener<T> listener : listeners) {
+ listener.onChange(oldLevel, newLevel);
+ }
+ }
+
+ protected abstract void setValue(String val) throws
InvalidConfigValueException;
+
+ protected abstract T getValue();
+
+ }
+
+ public NETWORK_THREAT_LEVEL getNetworkThreatLevel() {
+ return networkThreatLevel;
+ }
+
+}