Author: toad
Date: 2009-01-06 20:20:46 +0000 (Tue, 06 Jan 2009)
New Revision: 24928
Added:
trunk/freenet/src/freenet/clients/http/LinkFixer.java
trunk/freenet/src/freenet/clients/http/NullLinkFixer.java
Modified:
trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
trunk/freenet/src/freenet/node/Node.java
Log:
History cloaking: first stage:
Option to enable history cloaking.
When enabled, url's must include a ?secureid= parameter derived from the url
and the node's client nonce. If this is not set we send an error page
explaining this, asking the user to clear their browser history and ideally use
separate browsers for freenet vs internet, and pointing them to the fixed url.
Write the initial url to freenet.url. This can be used by browse.sh/browse.cmd
to open the correct page
Create a 32-byte client nonce. Write this to client-nonce.dat. If history
cloaking is enabled, create it before starting the web interface; on windows or
with /dev/urandom, this shouldn't cause a problem, otherwise it may cause the
first startup to block without showing the web interface if entropy is low.
Start the entropy gathering thread early in that case.
Move nodeDir setup to before creating SimpleToadletServer.
LinkFixer interface, implemented by SimpleToadletServer, will be used by
anything that needs to send links to the browser to add ?secureid='s.
Added: trunk/freenet/src/freenet/clients/http/LinkFixer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/LinkFixer.java
(rev 0)
+++ trunk/freenet/src/freenet/clients/http/LinkFixer.java 2009-01-06
20:20:46 UTC (rev 24928)
@@ -0,0 +1,12 @@
+package freenet.clients.http;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public interface LinkFixer {
+
+ public abstract String fixLink(String orig);
+
+ public abstract URI fixLink(URI uri) throws URISyntaxException;
+
+}
\ No newline at end of file
Added: trunk/freenet/src/freenet/clients/http/NullLinkFixer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/NullLinkFixer.java
(rev 0)
+++ trunk/freenet/src/freenet/clients/http/NullLinkFixer.java 2009-01-06
20:20:46 UTC (rev 24928)
@@ -0,0 +1,18 @@
+package freenet.clients.http;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public final class NullLinkFixer implements LinkFixer {
+
+ public static LinkFixer instance = new NullLinkFixer();
+
+ public final String fixLink(String orig) {
+ return orig;
+ }
+
+ public URI fixLink(URI uri) throws URISyntaxException {
+ return uri;
+ }
+
+}
Modified: trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
2009-01-06 17:20:44 UTC (rev 24927)
+++ trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
2009-01-06 20:20:46 UTC (rev 24928)
@@ -4,13 +4,17 @@
package freenet.clients.http;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.security.MessageDigest;
import java.util.Iterator;
import java.util.LinkedList;
@@ -20,13 +24,16 @@
import freenet.config.InvalidConfigValueException;
import freenet.config.NodeNeedRestartException;
import freenet.config.SubConfig;
+import freenet.crypt.SHA256;
import freenet.crypt.SSL;
import freenet.io.AllowedHosts;
import freenet.io.NetworkInterface;
import freenet.io.SSLNetworkInterface;
import freenet.keys.FreenetURI;
import freenet.l10n.L10n;
+import freenet.node.Node;
import freenet.node.NodeClientCore;
+import freenet.support.Base64;
import freenet.support.Executor;
import freenet.support.HTMLNode;
import freenet.support.Logger;
@@ -37,13 +44,14 @@
import freenet.support.api.LongCallback;
import freenet.support.api.StringCallback;
import freenet.support.io.ArrayBucketFactory;
+import freenet.support.io.Closer;
/**
* The Toadlet (HTTP) Server
*
* Provide a HTTP server for FProxy
*/
-public final class SimpleToadletServer implements ToadletContainer, Runnable {
+public final class SimpleToadletServer implements ToadletContainer, Runnable,
LinkFixer {
/** List of urlPrefix / Toadlet */
private final LinkedList<ToadletElement> toadlets;
private static class ToadletElement {
@@ -62,6 +70,8 @@
private NetworkInterface networkInterface;
private boolean ssl = false;
public static final int DEFAULT_FPROXY_PORT = 8888;
+ private byte[] clientNonce;
+ private final Node node;
// ACL
private final AllowedHosts allowedFullAccess;
@@ -83,6 +93,7 @@
private boolean doRobots;
private boolean enablePersistentConnections;
private boolean enableInlinePrefetch;
+ private boolean enableHistoryCloaking;
// Something does not really belongs to here
static boolean isPanicButtonToBeShown; // move
to QueueToadlet ?
@@ -286,6 +297,29 @@
}
}
+ private static class FProxyHistoryCloakingCallback extends
BooleanCallback {
+
+ FProxyHistoryCloakingCallback(SimpleToadletServer ts) {
+ this.ts = ts;
+ }
+
+ private final SimpleToadletServer ts;
+
+ @Override
+ public Boolean get() {
+ return ts.enableHistoryCloaking;
+ }
+
+ @Override
+ public void set(Boolean val) throws
InvalidConfigValueException, NodeNeedRestartException {
+ boolean enable = val;
+ if(enable == ts.enableHistoryCloaking) return;
+ this.ts.enableHistoryCloaking = enable;
+ this.ts.writeURLFile();
+ }
+
+ }
+
private boolean haveCalledFProxy = false;
public void createFproxy() {
@@ -305,6 +339,29 @@
+ public void writeURLFile() {
+ String url = "http://127.0.0.1:"+port;
+ if(enableHistoryCloaking)
+ url += fixLink("/");
+ else
+ url += "/";
+ File f = new File(node.getNodeDir(), "freenet.url");
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(f);
+ OutputStreamWriter osw = new OutputStreamWriter(fos);
// System charset better in this instance???
+ osw.write(url+(File.separatorChar == '\\' ? "\r" : "")
+ "\n");
+ osw.flush();
+ } catch (IOException e) {
+ Logger.error(this, "Unable to write URL "+url+" to
freenet.url: browse.sh/browse.cmd may have difficulty! : "+e, e);
+ System.err.println("Unable to write URL "+url+" to
freenet.url: browse.sh/browse.cmd may have difficulty! : "+e);
+ } finally {
+ Closer.close(fos);
+ }
+ }
+
+
+
public synchronized void setCore(NodeClientCore core) {
this.core = core;
}
@@ -313,9 +370,10 @@
* Create a SimpleToadletServer, using the settings from the SubConfig
(the fproxy.*
* config).
*/
- public SimpleToadletServer(SubConfig fproxyConfig, BucketFactory
bucketFactory, Executor executor) throws IOException,
InvalidConfigValueException {
+ public SimpleToadletServer(SubConfig fproxyConfig, BucketFactory
bucketFactory, Executor executor, Node node) throws IOException,
InvalidConfigValueException {
this.executor = executor;
+ this.node = node;
int configItemOrder = 0;
@@ -431,6 +489,10 @@
});
enableInlinePrefetch =
fproxyConfig.getBoolean("enableInlinePrefetch");
+ // Off by default, installer turns it on.
+ fproxyConfig.register("enableHistoryCloaking", false,
configItemOrder++, false, false, "SimpleToadletServer.enableHistoryCloaking",
"SimpleToadletServer.enableHistoryCloakingLong", new
FProxyHistoryCloakingCallback(this));
+ enableHistoryCloaking =
fproxyConfig.getBoolean("enableHistoryCloaking");
+
fproxyConfig.register("passthroughMaxSize", 2L*1024*1024,
configItemOrder++, true, false, "SimpleToadletServer.passthroughMaxSize",
"SimpleToadletServer.passthroughMaxSizeLong", new FProxyPassthruMaxSize());
FProxyToadlet.MAX_LENGTH =
fproxyConfig.getLong("passthroughMaxSize");
@@ -537,6 +599,7 @@
public void start() {
if(myThread != null) try {
+ writeURLFile();
maybeGetNetworkInterface();
myThread.start();
Logger.normal(this, "Starting FProxy on "+bindTo+ ':'
+port);
@@ -749,5 +812,60 @@
public synchronized BucketFactory getBucketFactory() {
return bf;
}
+
+ public String generateSID(String realPath) {
+ MessageDigest md = SHA256.getMessageDigest();
+ try {
+ md.update(realPath.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ md.update(clientNonce);
+ byte[] output = md.digest();
+ SHA256.returnMessageDigest(md);
+ return Base64.encode(output);
+ }
+
+ public boolean isSecureIDCheckingDisabled() {
+ return !enableHistoryCloaking;
+ }
+ /* (non-Javadoc)
+ * @see freenet.clients.http.LinkFixer#fixLink(java.lang.String)
+ */
+ public String fixLink(String orig) {
+ if(isSecureIDCheckingDisabled())
+ return orig;
+ String toSign = orig;
+ String frag = "";
+ int hashIndex = toSign.indexOf('#');
+ if(hashIndex != -1) {
+ frag = toSign.substring(hashIndex);
+ toSign = toSign.substring(0, hashIndex);
+ }
+ if(orig.indexOf('?') == -1) {
+ return toSign + "?secureid=" + generateSID(toSign) +
frag;
+ } else {
+ return toSign + "&secureid=" + generateSID(toSign) +
frag;
+ }
+ }
+
+ public URI fixLink(URI uri) throws URISyntaxException {
+ if(isSecureIDCheckingDisabled())
+ return uri;
+ String toSign = uri.toString();
+ if(uri.getFragment() != null) {
+ toSign = toSign.substring(0, toSign.indexOf('#'));
+ }
+ if(uri.getQuery() == null) {
+ return new URI(uri.getScheme(), uri.getUserInfo(),
uri.getHost(), uri.getPort(), uri.getPath(), "secureid="+generateSID(toSign),
uri.getFragment());
+ } else {
+ return new URI(uri.getScheme(), uri.getUserInfo(),
uri.getHost(), uri.getPort(), uri.getPath(),
uri.getQuery()+"&secureid="+generateSID(toSign), uri.getFragment());
+ }
+ }
+
+ public synchronized void setNonce(byte[] nonce) {
+ this.clientNonce = nonce;
+ }
+
}
Modified: trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
2009-01-06 17:20:44 UTC (rev 24927)
+++ trunk/freenet/src/freenet/clients/http/ToadletContextImpl.java
2009-01-06 20:20:46 UTC (rev 24928)
@@ -6,6 +6,7 @@
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URI;
@@ -36,7 +37,7 @@
* @author root
*
*/
-public class ToadletContextImpl implements ToadletContext {
+public class ToadletContextImpl implements ToadletContext, LinkFixer {
private final MultiValueTable<String,String> headers;
private final OutputStream sockOutputStream;
@@ -344,6 +345,7 @@
// Handle it.
try {
boolean redirect = true;
+ boolean first = true;
while (redirect) {
// don't go around the loop unless set
explicitly
redirect = false;
@@ -364,9 +366,11 @@
HTTPRequestImpl req = new
HTTPRequestImpl(uri, data, ctx);
try {
if(method.equals("GET")) {
- t.handleGet(uri, req,
ctx);
+ if(!(first &&
checkSecureID(uri, req, ctx)))
+
t.handleGet(uri, req, ctx);
ctx.close();
} else
if(method.equals("POST")) {
+ // FIXME check the
?secureid= for POSTs ... necessary?
t.handlePost(uri, req,
ctx);
} else {
ctx.sendMethodNotAllowed(method, ctx.shouldDisconnect);
@@ -375,6 +379,7 @@
} catch (RedirectException re) {
uri = re.newuri;
redirect = true;
+ first = false;
} finally {
req.freeParts();
}
@@ -411,6 +416,103 @@
}
/**
+ * Check a request for a valid secureid parameter. This is used to
ensure that no predictable uri goes
+ * into the browser history. The secureid parameter is generated from
the client nonce and the uri,
+ * including the ? parameters except for the secureid.
+ * @param uri
+ * @param req
+ * @param ctx
+ * @return True if we sent a warning message to the user and the
request need not be handled further,
+ * false if there is a valid secureid parameter.
+ * @throws IOException
+ * @throws ToadletContextClosedException
+ */
+ private static boolean checkSecureID(URI uri, HTTPRequestImpl req,
ToadletContextImpl ctx) throws ToadletContextClosedException, IOException {
+ if(ctx.container.isSecureIDCheckingDisabled()) {
+ return false;
+ }
+ String path = uri.getRawPath();
+ String secureid = req.getParam("secureid"); // remove it
+ String queries = getQueriesNoSecureID(uri);
+ String realPath = path;
+ if(queries != null) realPath += queries;
+ String expectedSecureID = ctx.container.generateSID(realPath);
+ if(secureid != null && expectedSecureID.equals(secureid)) {
+ return false;
+ }
+
+ // Warn the user.
+
+ HTMLNode pageNode =
ctx.getPageMaker().getPageNode(l10n("browserHistoryWarningTitle"), ctx);
+ HTMLNode contentNode =
ctx.getPageMaker().getContentNode(pageNode);
+ HTMLNode warningBox = contentNode.addChild("div", "class", "infobox
infobox-normal");
+ HTMLNode warningBoxHeader = warningBox.addChild("div", "class",
"infobox-header");
+ warningBoxHeader.addChild("#", l10n("browserHistoryWarningBoxTitle"));
+ HTMLNode warningBoxContent = warningBox.addChild("div", "class",
"infobox-content");
+ warningBoxContent.addChild("p", l10n("browserHistoryWarning"));
+
+ // Link to the page
+ if(queries == null) queries = "?secureid="+expectedSecureID;
+ else queries += "&secureid="+expectedSecureID;
+ realPath = path + queries;
+ L10n.addL10nSubstitution(warningBoxContent,
"ToadletContextImpl.browserHistoryWarningLink",
+ new String[] { "link", "/link" },
+ new String[] { "<a
href=\""+HTMLEncoder.encode(realPath)+"\">", "</a>" });
+
+ if(ctx.isAllowedFullAccess()) {
+ // Button to disable the warning
+ // FIXME implement
+ }
+
+ byte[] data;
+ try {
+ data = pageNode.generate().getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+
+ ctx.sendReplyHeaders(400, "Bad Request", null, "text/html;
charset=utf-8", data.length);
+ ctx.writeData(data);
+
+ return true;
+ }
+
+ private static String getQueriesNoSecureID(URI uri) {
+ String query = uri.getQuery();
+ if(query == null) return null;
+ if(query.startsWith("secureid=")) {
+ query = query.substring("secureid=".length());
+ int x = query.indexOf('&');
+ if(x >= 0)
+ return '?' + query.substring(x+1);
+ else return null;
+ } else {
+ int idx = query.indexOf("&secureid=");
+ if(idx == -1) return query;
+ String before = query.substring(0, idx);
+ String after =
query.substring(idx+"&secureid=".length());
+ int x = after.indexOf('&');
+ if(x >= 0) {
+ after = after.substring(x+1);
+ return '?' + before + '&' + after;
+ } else {
+ return '?' + before;
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see freenet.clients.http.LinkFixer#fixLink(java.lang.String)
+ */
+ public String fixLink(String orig) {
+ return container.fixLink(orig);
+ }
+
+ public URI fixLink(URI uri) throws URISyntaxException {
+ return container.fixLink(uri);
+ }
+
+ /**
* Should the connection be closed after handling this request?
* @param isHTTP10 Did the client specify HTTP/1.0?
* @param headers Client headers.
@@ -478,4 +580,5 @@
public ToadletContainer getContainer() {
return container;
}
+
}
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2009-01-06 17:20:44 UTC (rev
24927)
+++ trunk/freenet/src/freenet/node/Node.java 2009-01-06 20:20:46 UTC (rev
24928)
@@ -2,6 +2,7 @@
package freenet.node;
import java.io.BufferedReader;
+import java.io.DataInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
@@ -13,6 +14,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.MessageDigest;
+import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -34,6 +36,7 @@
import com.sleepycat.je.StatsConfig;
import freenet.client.FetchContext;
+import freenet.clients.http.LinkFixer;
import freenet.clients.http.SimpleToadletServer;
import freenet.config.EnumerableOptionCallback;
import freenet.config.FreenetFilePersistentConfig;
@@ -663,12 +666,139 @@
L10n.setLanguage(L10n.LANGUAGE.getDefault().shortCode);
}
}
+
+ // 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",
+ new StringCallback() {
+ @Override
+ public String get() {
+ return nodeDir.getPath();
+ }
+ @Override
+ public void set(String val) throws
InvalidConfigValueException {
+ if(nodeDir.equals(new
File(val))) return;
+ // FIXME support it
+ // Don't translate the below as
very few users will use it.
+ throw new
InvalidConfigValueException("Moving node directory on the fly not supported at
present");
+ }
+ @Override
+ public boolean isReadOnly() {
+ return true;
+ }
+ });
+
+ nodeDir = new File(nodeConfig.getString("nodeDir"));
+ if(!((nodeDir.exists() && nodeDir.isDirectory()) ||
(nodeDir.mkdir()))) {
+ String msg = "Could not find or create datastore
directory";
+ throw new
NodeInitException(NodeInitException.EXIT_BAD_NODE_DIR, msg);
+ }
+
+ File clientNonceFile = new File(nodeDir, "client-nonce.dat");
+ byte[] nonce = null;
+
+ final NativeThread entropyGatheringThread = new
NativeThread(new Runnable() {
+
+ private void recurse(File f) {
+ if(isPRNGReady)
+ return;
+ File[] subDirs = f.listFiles(new FileFilter() {
+
+ public boolean accept(File pathname) {
+ return pathname.exists() &&
pathname.canRead() && pathname.isDirectory();
+ }
+ });
+
+
+ // @see
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5086412
+ if(subDirs != null)
+ for(File currentDir : subDirs)
+ recurse(currentDir);
+ }
+
+ public void run() {
+ for(File root : File.listRoots()) {
+ if(isPRNGReady)
+ return;
+ recurse(root);
+ }
+ }
+ }, "Entropy Gathering Thread", NativeThread.MIN_PRIORITY, true);
+ boolean startedEntropyGatherer = false;
+
// FProxy config needs to be here too
SubConfig fproxyConfig = new SubConfig("fproxy", config);
try {
- toadlets = new SimpleToadletServer(fproxyConfig, new
ArrayBucketFactory(), executor);
+ toadlets = new SimpleToadletServer(fproxyConfig, new
ArrayBucketFactory(), executor, this);
fproxyConfig.finishedInitialization();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(clientNonceFile);
+ DataInputStream dis = new DataInputStream(fis);
+ nonce = new byte[32];
+ dis.readFully(nonce);
+ } catch (IOException e) {
+ nonce = null;
+ } finally {
+ Closer.close(fis);
+ }
+ if(nonce == null &&
!toadlets.isSecureIDCheckingDisabled()) {
+ // Generate client-nonce.
+ class Wrapper {
+ boolean finished;
+ byte[] result;
+ }
+ final Wrapper w = new Wrapper();
+ Thread t = new Thread(new Runnable() {
+
+ public void run() {
+ byte[] result =
SecureRandom.getSeed(32);
+ synchronized(w) {
+ w.result = result;
+ w.finished = true;
+ }
+ }
+
+ }, "History cloaking seed thread");
+ t.start();
+ synchronized(w) {
+ if(!w.finished) {
+ try {
+ w.wait(5000);
+ } catch (InterruptedException
e) {
+ // Ignore
+ } // Give it 5 seconds...
+ }
+ nonce = w.result;
+ }
+ if(nonce == null) {
+ if(File.separatorChar == '/') {
+ File urandom = new
File("/dev/urandom");
+ if(urandom.exists()) {
+ fis = null;
+ nonce = new byte[32];
+ try {
+ fis = new
FileInputStream(urandom);
+ DataInputStream
dis = new DataInputStream(fis);
+
dis.readFully(nonce);
+ } catch (IOException e)
{
+ nonce = null;
+ } finally {
+
Closer.close(fis);
+ }
+ }
+ }
+ }
+ if(nonce == null) {
+ // Either we are on Windows, in which
case CAPI doesn't block, or we are on some wierd unix...
+ System.err.println("Blocking waiting
for entropy. Because history cloaking is enabled, we cannot yet launch the web
interface...");
+ entropyGatheringThread.start();
+ startedEntropyGatherer = true;
+ nonce = SecureRandom.getSeed(32);
+ }
+ writeClientNonce(nonce, clientNonceFile);
+ }
+ toadlets.setNonce(nonce);
toadlets.start();
} catch (IOException e4) {
Logger.error(this, "Could not start web interface:
"+e4, e4);
@@ -680,38 +810,11 @@
e4.printStackTrace();
throw new
NodeInitException(NodeInitException.EXIT_COULD_NOT_START_FPROXY, "Could not
start FProxy: "+e4);
}
-
+
// Setup RNG if needed : DO NOT USE IT BEFORE THAT POINT!
if(r == null) {
- final NativeThread entropyGatheringThread = new
NativeThread(new Runnable() {
-
- private void recurse(File f) {
- if(isPRNGReady)
- return;
- File[] subDirs = f.listFiles(new
FileFilter() {
-
- public boolean accept(File
pathname) {
- return
pathname.exists() && pathname.canRead() && pathname.isDirectory();
- }
- });
-
-
- // @see
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5086412
- if(subDirs != null)
- for(File currentDir : subDirs)
- recurse(currentDir);
- }
-
- public void run() {
- for(File root : File.listRoots()) {
- if(isPRNGReady)
- return;
- recurse(root);
- }
- }
- }, "Entropy Gathering Thread",
NativeThread.MIN_PRIORITY, true);
-
- entropyGatheringThread.start();
+ if(!startedEntropyGatherer)
+ entropyGatheringThread.start();
this.random = new Yarrow();
DiffieHellman.init(random);
@@ -719,6 +822,14 @@
this.random = r;
isPRNGReady = true;
toadlets.getStartupToadlet().setIsPRNGReady();
+
+ if(nonce == null) {
+ nonce = new byte[32];
+ random.nextBytes(nonce);
+ toadlets.setNonce(nonce);
+ }
+ writeClientNonce(nonce, clientNonceFile);
+
if(weakRandom == null) {
byte buffer[] = new byte[16];
random.nextBytes(buffer);
@@ -757,33 +868,6 @@
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",
- new StringCallback() {
- @Override
- public String get() {
- return nodeDir.getPath();
- }
- @Override
- public void set(String val) throws
InvalidConfigValueException {
- if(nodeDir.equals(new
File(val))) return;
- // FIXME support it
- // Don't translate the below as
very few users will use it.
- throw new
InvalidConfigValueException("Moving node directory on the fly not supported at
present");
- }
- @Override
- public boolean isReadOnly() {
- return true;
- }
- });
-
- nodeDir = new File(nodeConfig.getString("nodeDir"));
- if(!((nodeDir.exists() && nodeDir.isDirectory()) ||
(nodeDir.mkdir()))) {
- String msg = "Could not find or create datastore
directory";
- throw new
NodeInitException(NodeInitException.EXIT_BAD_NODE_DIR, msg);
- }
-
// Boot ID
bootID = random.nextLong();
// Fixed length file containing boot ID. Accessed with random
access file. So hopefully it will always be
@@ -1891,6 +1975,19 @@
System.out.println("Node constructor completed");
}
+ private void writeClientNonce(byte[] nonce, File nonceFile) {
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(nonceFile);
+ fos.write(nonce);
+ fos.flush();
+ } catch (IOException e) {
+ System.err.println("Failed to write client nonce. This
means that fproxy URLs will be different on every restart. Reason: "+e);
+ } finally {
+ Closer.close(fos);
+ }
+ }
+
private void initSaltHashFS(final String suffix) throws
NodeInitException {
storeEnvironment = null;
envMutableConfig = null;
@@ -2248,7 +2345,7 @@
HTMLNode n = new
HTMLNode("div");
L10n.addL10nSubstitution(n,
"Node.buggyJVMWithLink",
new String[] {
"link", "/link", "version" },
- new String[] {
"<a
href=\"/?_CHECKED_HTTP_=http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4855795\">",
+ new String[] {
"<a
href=\"/?_CHECKED_HTTP_=http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4855795\">",
"</a>",
HTMLEncoder.encode(System.getProperty("java.version")) });
return n;
}
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs