merge of '3b6c4d6af6fae83cc9b7d42e8515804ae48ec675'
and '799a00a4929a59478c534a56cce350cdb9a042e0'
This commit is contained in:
@ -68,6 +68,10 @@ Public domain except as listed below:
|
|||||||
Copyright (C) 2001, 2007 Free Software Foundation, Inc.
|
Copyright (C) 2001, 2007 Free Software Foundation, Inc.
|
||||||
See licenses/LICENSE-LGPLv2.1.txt
|
See licenses/LICENSE-LGPLv2.1.txt
|
||||||
|
|
||||||
|
SSLEepGet:
|
||||||
|
Contains some code Copyright 2006 Sun Microsystems, Inc.
|
||||||
|
See licenses/LICENSE-InstallCert.txt
|
||||||
|
|
||||||
|
|
||||||
Router:
|
Router:
|
||||||
Public domain except as listed below:
|
Public domain except as listed below:
|
||||||
|
@ -49,6 +49,8 @@ import net.i2p.util.SecureFileOutputStream;
|
|||||||
*/
|
*/
|
||||||
class ConfigParser {
|
class ConfigParser {
|
||||||
|
|
||||||
|
private static final boolean isWindows = System.getProperty("os.name").startsWith("Win");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip the comments from a String. Lines that begin with '#' and ';' are
|
* Strip the comments from a String. Lines that begin with '#' and ';' are
|
||||||
* considered comments, as well as any part of a line after a '#'.
|
* considered comments, as well as any part of a line after a '#'.
|
||||||
@ -276,7 +278,8 @@ class ConfigParser {
|
|||||||
* Write contents of Map map to the File file. Output is written
|
* Write contents of Map map to the File file. Output is written
|
||||||
* with one key, value pair on each line, in the format: key=value.
|
* with one key, value pair on each line, in the format: key=value.
|
||||||
* Write to a temp file in the same directory and then rename, to not corrupt
|
* Write to a temp file in the same directory and then rename, to not corrupt
|
||||||
* simultaneous accesses by the router.
|
* simultaneous accesses by the router. Except on Windows where renameTo()
|
||||||
|
* will fail if the target exists.
|
||||||
*
|
*
|
||||||
* @param map
|
* @param map
|
||||||
* A Map to write to file.
|
* A Map to write to file.
|
||||||
@ -286,14 +289,19 @@ class ConfigParser {
|
|||||||
* if file cannot be written to.
|
* if file cannot be written to.
|
||||||
*/
|
*/
|
||||||
public static void write(Map map, File file) throws IOException {
|
public static void write(Map map, File file) throws IOException {
|
||||||
File tmp = SecureFile.createTempFile("hoststxt-", ".tmp", file.getAbsoluteFile().getParentFile());
|
boolean success = false;
|
||||||
ConfigParser
|
if (!isWindows) {
|
||||||
|
File tmp = SecureFile.createTempFile("temp-", ".tmp", file.getAbsoluteFile().getParentFile());
|
||||||
|
ConfigParser
|
||||||
.write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(tmp), "UTF-8")));
|
.write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(tmp), "UTF-8")));
|
||||||
boolean success = tmp.renameTo(file);
|
success = tmp.renameTo(file);
|
||||||
|
if (!success) {
|
||||||
|
tmp.delete();
|
||||||
|
//System.out.println("Warning: addressbook rename fail from " + tmp + " to " + file);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// hmm, that didn't work, try it the old way
|
// hmm, that didn't work, try it the old way
|
||||||
System.out.println("Warning: addressbook rename fail from " + tmp + " to " + file);
|
|
||||||
tmp.delete();
|
|
||||||
ConfigParser
|
ConfigParser
|
||||||
.write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
|
.write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
|
||||||
}
|
}
|
||||||
|
14
apps/i2psnark/java/src/org/klomp/snark/DataLoader.java
Normal file
14
apps/i2psnark/java/src/org/klomp/snark/DataLoader.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package org.klomp.snark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used to fetch data
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
interface DataLoader
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This is the callback that PeerConnectionOut calls to get the data from disk
|
||||||
|
* @return bytes or null for errors
|
||||||
|
*/
|
||||||
|
public byte[] loadData(int piece, int begin, int length);
|
||||||
|
}
|
@ -39,23 +39,28 @@ class Message
|
|||||||
final static byte REQUEST = 6;
|
final static byte REQUEST = 6;
|
||||||
final static byte PIECE = 7;
|
final static byte PIECE = 7;
|
||||||
final static byte CANCEL = 8;
|
final static byte CANCEL = 8;
|
||||||
|
final static byte EXTENSION = 20;
|
||||||
|
|
||||||
// Not all fields are used for every message.
|
// Not all fields are used for every message.
|
||||||
// KEEP_ALIVE doesn't have a real wire representation
|
// KEEP_ALIVE doesn't have a real wire representation
|
||||||
byte type;
|
byte type;
|
||||||
|
|
||||||
// Used for HAVE, REQUEST, PIECE and CANCEL messages.
|
// Used for HAVE, REQUEST, PIECE and CANCEL messages.
|
||||||
|
// low byte used for EXTENSION message
|
||||||
int piece;
|
int piece;
|
||||||
|
|
||||||
// Used for REQUEST, PIECE and CANCEL messages.
|
// Used for REQUEST, PIECE and CANCEL messages.
|
||||||
int begin;
|
int begin;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
// Used for PIECE and BITFIELD messages
|
// Used for PIECE and BITFIELD and EXTENSION messages
|
||||||
byte[] data;
|
byte[] data;
|
||||||
int off;
|
int off;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
// Used to do deferred fetch of data
|
||||||
|
DataLoader dataLoader;
|
||||||
|
|
||||||
SimpleTimer.TimedEvent expireEvent;
|
SimpleTimer.TimedEvent expireEvent;
|
||||||
|
|
||||||
/** Utility method for sending a message through a DataStream. */
|
/** Utility method for sending a message through a DataStream. */
|
||||||
@ -68,6 +73,13 @@ class Message
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get deferred data
|
||||||
|
if (data == null && dataLoader != null) {
|
||||||
|
data = dataLoader.loadData(piece, begin, length);
|
||||||
|
if (data == null)
|
||||||
|
return; // hmm will get retried, but shouldn't happen
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the total length in bytes
|
// Calculate the total length in bytes
|
||||||
|
|
||||||
// Type is one byte.
|
// Type is one byte.
|
||||||
@ -85,8 +97,12 @@ class Message
|
|||||||
if (type == REQUEST || type == CANCEL)
|
if (type == REQUEST || type == CANCEL)
|
||||||
datalen += 4;
|
datalen += 4;
|
||||||
|
|
||||||
|
// length is 1 byte
|
||||||
|
if (type == EXTENSION)
|
||||||
|
datalen += 1;
|
||||||
|
|
||||||
// add length of data for piece or bitfield array.
|
// add length of data for piece or bitfield array.
|
||||||
if (type == BITFIELD || type == PIECE)
|
if (type == BITFIELD || type == PIECE || type == EXTENSION)
|
||||||
datalen += len;
|
datalen += len;
|
||||||
|
|
||||||
// Send length
|
// Send length
|
||||||
@ -105,8 +121,11 @@ class Message
|
|||||||
if (type == REQUEST || type == CANCEL)
|
if (type == REQUEST || type == CANCEL)
|
||||||
dos.writeInt(length);
|
dos.writeInt(length);
|
||||||
|
|
||||||
|
if (type == EXTENSION)
|
||||||
|
dos.writeByte((byte) piece & 0xff);
|
||||||
|
|
||||||
// Send actual data
|
// Send actual data
|
||||||
if (type == BITFIELD || type == PIECE)
|
if (type == BITFIELD || type == PIECE || type == EXTENSION)
|
||||||
dos.write(data, off, len);
|
dos.write(data, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +154,8 @@ class Message
|
|||||||
return "PIECE(" + piece + "," + begin + "," + length + ")";
|
return "PIECE(" + piece + "," + begin + "," + length + ")";
|
||||||
case CANCEL:
|
case CANCEL:
|
||||||
return "CANCEL(" + piece + "," + begin + "," + length + ")";
|
return "CANCEL(" + piece + "," + begin + "," + length + ")";
|
||||||
|
case EXTENSION:
|
||||||
|
return "EXTENSION(" + piece + ',' + data.length + ')';
|
||||||
default:
|
default:
|
||||||
return "<UNKNOWN>";
|
return "<UNKNOWN>";
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,11 @@ public class Peer implements Comparable
|
|||||||
private long uploaded_old[] = {-1,-1,-1};
|
private long uploaded_old[] = {-1,-1,-1};
|
||||||
private long downloaded_old[] = {-1,-1,-1};
|
private long downloaded_old[] = {-1,-1,-1};
|
||||||
|
|
||||||
|
// bytes per bt spec: 0011223344556677
|
||||||
|
static final long OPTION_EXTENSION = 0x0000000000100000l;
|
||||||
|
static final long OPTION_FAST = 0x0000000000000004l;
|
||||||
|
private long options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a disconnected peer given a PeerID, your own id and the
|
* Creates a disconnected peer given a PeerID, your own id and the
|
||||||
* relevant MetaInfo.
|
* relevant MetaInfo.
|
||||||
@ -285,9 +290,8 @@ public class Peer implements Comparable
|
|||||||
// Handshake write - header
|
// Handshake write - header
|
||||||
dout.write(19);
|
dout.write(19);
|
||||||
dout.write("BitTorrent protocol".getBytes("UTF-8"));
|
dout.write("BitTorrent protocol".getBytes("UTF-8"));
|
||||||
// Handshake write - zeros
|
// Handshake write - options
|
||||||
byte[] zeros = new byte[8];
|
dout.writeLong(OPTION_EXTENSION);
|
||||||
dout.write(zeros);
|
|
||||||
// Handshake write - metainfo hash
|
// Handshake write - metainfo hash
|
||||||
byte[] shared_hash = metainfo.getInfoHash();
|
byte[] shared_hash = metainfo.getInfoHash();
|
||||||
dout.write(shared_hash);
|
dout.write(shared_hash);
|
||||||
@ -312,8 +316,8 @@ public class Peer implements Comparable
|
|||||||
+ "'Bittorrent protocol', got '"
|
+ "'Bittorrent protocol', got '"
|
||||||
+ bittorrentProtocol + "'");
|
+ bittorrentProtocol + "'");
|
||||||
|
|
||||||
// Handshake read - zeros
|
// Handshake read - options
|
||||||
din.readFully(zeros);
|
options = din.readLong();
|
||||||
|
|
||||||
// Handshake read - metainfo hash
|
// Handshake read - metainfo hash
|
||||||
bs = new byte[20];
|
bs = new byte[20];
|
||||||
@ -325,6 +329,15 @@ public class Peer implements Comparable
|
|||||||
din.readFully(bs);
|
din.readFully(bs);
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Read the remote side's hash and peerID fully from " + toString());
|
_log.debug("Read the remote side's hash and peerID fully from " + toString());
|
||||||
|
|
||||||
|
// if ((options & OPTION_EXTENSION) != 0) {
|
||||||
|
if (options != 0) {
|
||||||
|
// send them something
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
//_log.debug("Peer supports extension message, what should we say? " + toString());
|
||||||
|
_log.debug("Peer supports options 0x" + Long.toString(options, 16) + ", what should we say? " + toString());
|
||||||
|
}
|
||||||
|
|
||||||
return bs;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +171,13 @@ class PeerConnectionIn implements Runnable
|
|||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Received cancel(" + piece + "," + begin + ") from " + peer + " on " + peer.metainfo.getName());
|
_log.debug("Received cancel(" + piece + "," + begin + ") from " + peer + " on " + peer.metainfo.getName());
|
||||||
break;
|
break;
|
||||||
|
case 20: // Extension message
|
||||||
|
int id = din.readUnsignedByte();
|
||||||
|
byte[] payload = new byte[i-2];
|
||||||
|
din.readFully(payload);
|
||||||
|
ps.extensionMessage(id, payload);
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Received extension message from " + peer + " on " + peer.metainfo.getName());
|
||||||
default:
|
default:
|
||||||
byte[] bs = new byte[i-1];
|
byte[] bs = new byte[i-1];
|
||||||
din.readFully(bs);
|
din.readFully(bs);
|
||||||
|
@ -430,6 +430,33 @@ class PeerConnectionOut implements Runnable
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.2 */
|
||||||
|
void sendPiece(int piece, int begin, int length, DataLoader loader)
|
||||||
|
{
|
||||||
|
boolean sendNow = false;
|
||||||
|
// are there any cases where we should?
|
||||||
|
|
||||||
|
if (sendNow) {
|
||||||
|
// queue the real thing
|
||||||
|
byte[] bytes = loader.loadData(piece, begin, length);
|
||||||
|
if (bytes != null)
|
||||||
|
sendPiece(piece, begin, length, bytes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// queue a fake message... set everything up,
|
||||||
|
// except save the PeerState instead of the bytes.
|
||||||
|
Message m = new Message();
|
||||||
|
m.type = Message.PIECE;
|
||||||
|
m.piece = piece;
|
||||||
|
m.begin = begin;
|
||||||
|
m.length = length;
|
||||||
|
m.dataLoader = loader;
|
||||||
|
m.off = 0;
|
||||||
|
m.len = length;
|
||||||
|
addMessage(m);
|
||||||
|
}
|
||||||
|
|
||||||
void sendPiece(int piece, int begin, int length, byte[] bytes)
|
void sendPiece(int piece, int begin, int length, byte[] bytes)
|
||||||
{
|
{
|
||||||
Message m = new Message();
|
Message m = new Message();
|
||||||
@ -488,4 +515,16 @@ class PeerConnectionOut implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.2 */
|
||||||
|
void sendExtension(int id, byte[] bytes) {
|
||||||
|
Message m = new Message();
|
||||||
|
m.type = Message.EXTENSION;
|
||||||
|
m.piece = id;
|
||||||
|
m.data = bytes;
|
||||||
|
m.begin = 0;
|
||||||
|
m.length = bytes.length;
|
||||||
|
addMessage(m);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,20 @@
|
|||||||
|
|
||||||
package org.klomp.snark;
|
package org.klomp.snark;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
class PeerState
|
import org.klomp.snark.bencode.BDecoder;
|
||||||
|
import org.klomp.snark.bencode.BEValue;
|
||||||
|
|
||||||
|
class PeerState implements DataLoader
|
||||||
{
|
{
|
||||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
|
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
|
||||||
final Peer peer;
|
final Peer peer;
|
||||||
@ -201,13 +207,28 @@ class PeerState
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Queueing (" + piece + ", " + begin + ", "
|
||||||
|
+ length + ")" + " to " + peer);
|
||||||
|
|
||||||
|
// don't load the data into mem now, let PeerConnectionOut do it
|
||||||
|
out.sendPiece(piece, begin, length, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the callback that PeerConnectionOut calls
|
||||||
|
*
|
||||||
|
* @return bytes or null for errors
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public byte[] loadData(int piece, int begin, int length) {
|
||||||
byte[] pieceBytes = listener.gotRequest(peer, piece, begin, length);
|
byte[] pieceBytes = listener.gotRequest(peer, piece, begin, length);
|
||||||
if (pieceBytes == null)
|
if (pieceBytes == null)
|
||||||
{
|
{
|
||||||
// XXX - Protocol error-> diconnect?
|
// XXX - Protocol error-> diconnect?
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Got request for unknown piece: " + piece);
|
_log.warn("Got request for unknown piece: " + piece);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// More sanity checks
|
// More sanity checks
|
||||||
@ -219,13 +240,13 @@ class PeerState
|
|||||||
+ ", " + begin
|
+ ", " + begin
|
||||||
+ ", " + length
|
+ ", " + length
|
||||||
+ "' message from " + peer);
|
+ "' message from " + peer);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Sending (" + piece + ", " + begin + ", "
|
_log.info("Sending (" + piece + ", " + begin + ", "
|
||||||
+ length + ")" + " to " + peer);
|
+ length + ")" + " to " + peer);
|
||||||
out.sendPiece(piece, begin, length, pieceBytes);
|
return pieceBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -413,6 +434,24 @@ class PeerState
|
|||||||
out.cancelRequest(piece, begin, length);
|
out.cancelRequest(piece, begin, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.2 */
|
||||||
|
void extensionMessage(int id, byte[] bs)
|
||||||
|
{
|
||||||
|
if (id == 0) {
|
||||||
|
InputStream is = new ByteArrayInputStream(bs);
|
||||||
|
try {
|
||||||
|
BDecoder dec = new BDecoder(is);
|
||||||
|
BEValue bev = dec.bdecodeMap();
|
||||||
|
Map map = bev.getMap();
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Got extension handshake message " + bev.toString());
|
||||||
|
} catch (Exception e) {}
|
||||||
|
} else {
|
||||||
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Got extended message type: " + id + " length: " + bs.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void unknownMessage(int type, byte[] bs)
|
void unknownMessage(int type, byte[] bs)
|
||||||
{
|
{
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
@ -242,6 +242,13 @@ public class I2PSnarkServlet extends Default {
|
|||||||
|
|
||||||
List snarks = getSortedSnarks(req);
|
List snarks = getSortedSnarks(req);
|
||||||
String uri = req.getRequestURI();
|
String uri = req.getRequestURI();
|
||||||
|
boolean isForm = _manager.util().connected() || !snarks.isEmpty();
|
||||||
|
if (isForm) {
|
||||||
|
out.write("<form action=\"");
|
||||||
|
out.write(uri);
|
||||||
|
out.write("\" method=\"POST\">\n");
|
||||||
|
out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n");
|
||||||
|
}
|
||||||
out.write(TABLE_HEADER);
|
out.write(TABLE_HEADER);
|
||||||
out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/status.png\"");
|
out.write("<img border=\"0\" src=\"/themes/snark/ubergine/images/status.png\"");
|
||||||
out.write(" title=\"");
|
out.write(" title=\"");
|
||||||
@ -301,25 +308,17 @@ public class I2PSnarkServlet extends Default {
|
|||||||
out.write("</th>\n");
|
out.write("</th>\n");
|
||||||
out.write("<th align=\"center\">");
|
out.write("<th align=\"center\">");
|
||||||
if (_manager.util().connected()) {
|
if (_manager.util().connected()) {
|
||||||
out.write("<a href=\"" + uri + "?action=StopAll&nonce=" + _nonce +
|
out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
|
||||||
"\" title=\"");
|
|
||||||
out.write(_("Stop all torrents and the I2P tunnel"));
|
out.write(_("Stop all torrents and the I2P tunnel"));
|
||||||
out.write("\">");
|
out.write("\" src=\"/themes/snark/ubergine/images/stop_all.png\" alt=\"");
|
||||||
out.write("<img src=\"/themes/snark/ubergine/images/stop_all.png\" title=\"");
|
|
||||||
out.write(_("Stop all torrents and the I2P tunnel"));
|
|
||||||
out.write("\" alt=\"");
|
|
||||||
out.write(_("Stop All"));
|
out.write(_("Stop All"));
|
||||||
out.write("\">");
|
out.write("\">");
|
||||||
out.write("</a>");
|
|
||||||
} else if (!snarks.isEmpty()) {
|
} else if (!snarks.isEmpty()) {
|
||||||
out.write("<a href=\"" + uri + "?action=StartAll&nonce=" + _nonce +
|
out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\"");
|
||||||
"\" title=\"");
|
|
||||||
out.write(_("Start all torrents and the I2P tunnel"));
|
out.write(_("Start all torrents and the I2P tunnel"));
|
||||||
|
out.write("\" src=\"/themes/snark/ubergine/images/start_all.png\" alt=\"");
|
||||||
|
out.write(_("Start All"));
|
||||||
out.write("\">");
|
out.write("\">");
|
||||||
out.write("<img src=\"/themes/snark/ubergine/images/start_all.png\" title=\"");
|
|
||||||
out.write(_("Start all torrents and the I2P tunnel"));
|
|
||||||
out.write("\" alt=\"Start All\">");
|
|
||||||
out.write("</a>");
|
|
||||||
} else {
|
} else {
|
||||||
out.write(" ");
|
out.write(" ");
|
||||||
}
|
}
|
||||||
@ -357,6 +356,8 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.write("</table>");
|
out.write("</table>");
|
||||||
|
if (isForm)
|
||||||
|
out.write("</form>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -366,7 +367,11 @@ public class I2PSnarkServlet extends Default {
|
|||||||
String action = req.getParameter("action");
|
String action = req.getParameter("action");
|
||||||
if (action == null) {
|
if (action == null) {
|
||||||
// noop
|
// noop
|
||||||
} else if ("Add".equals(action)) {
|
return;
|
||||||
|
}
|
||||||
|
if (!"POST".equals(req.getMethod()))
|
||||||
|
return;
|
||||||
|
if ("Add".equals(action)) {
|
||||||
String newFile = req.getParameter("newFile");
|
String newFile = req.getParameter("newFile");
|
||||||
String newURL = req.getParameter("newURL");
|
String newURL = req.getParameter("newURL");
|
||||||
// NOTE - newFile currently disabled in HTML form - see below
|
// NOTE - newFile currently disabled in HTML form - see below
|
||||||
@ -410,8 +415,8 @@ public class I2PSnarkServlet extends Default {
|
|||||||
} else {
|
} else {
|
||||||
// no file or URL specified
|
// no file or URL specified
|
||||||
}
|
}
|
||||||
} else if ("Stop".equals(action)) {
|
} else if (action.startsWith("Stop_")) {
|
||||||
String torrent = req.getParameter("torrent");
|
String torrent = action.substring(5);
|
||||||
if (torrent != null) {
|
if (torrent != null) {
|
||||||
byte infoHash[] = Base64.decode(torrent);
|
byte infoHash[] = Base64.decode(torrent);
|
||||||
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
||||||
@ -425,8 +430,8 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("Start".equals(action)) {
|
} else if (action.startsWith("Start_")) {
|
||||||
String torrent = req.getParameter("torrent");
|
String torrent = action.substring(6);
|
||||||
if (torrent != null) {
|
if (torrent != null) {
|
||||||
byte infoHash[] = Base64.decode(torrent);
|
byte infoHash[] = Base64.decode(torrent);
|
||||||
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
||||||
@ -441,8 +446,8 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("Remove".equals(action)) {
|
} else if (action.startsWith("Remove_")) {
|
||||||
String torrent = req.getParameter("torrent");
|
String torrent = action.substring(7);
|
||||||
if (torrent != null) {
|
if (torrent != null) {
|
||||||
byte infoHash[] = Base64.decode(torrent);
|
byte infoHash[] = Base64.decode(torrent);
|
||||||
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
||||||
@ -461,8 +466,8 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ("Delete".equals(action)) {
|
} else if (action.startsWith("Delete_")) {
|
||||||
String torrent = req.getParameter("torrent");
|
String torrent = action.substring(7);
|
||||||
if (torrent != null) {
|
if (torrent != null) {
|
||||||
byte infoHash[] = Base64.decode(torrent);
|
byte infoHash[] = Base64.decode(torrent);
|
||||||
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
|
||||||
@ -618,10 +623,10 @@ public class I2PSnarkServlet extends Default {
|
|||||||
if (r.startsWith(skip))
|
if (r.startsWith(skip))
|
||||||
r = r.substring(skip.length());
|
r = r.substring(skip.length());
|
||||||
String llc = l.toLowerCase();
|
String llc = l.toLowerCase();
|
||||||
if (llc.startsWith("the ") || llc.startsWith("the."))
|
if (llc.startsWith("the ") || llc.startsWith("the.") || llc.startsWith("the_"))
|
||||||
l = l.substring(4);
|
l = l.substring(4);
|
||||||
String rlc = r.toLowerCase();
|
String rlc = r.toLowerCase();
|
||||||
if (rlc.startsWith("the ") || rlc.startsWith("the."))
|
if (rlc.startsWith("the ") || rlc.startsWith("the.") || rlc.startsWith("the_"))
|
||||||
r = r.substring(4);
|
r = r.substring(4);
|
||||||
return collator.compare(l, r);
|
return collator.compare(l, r);
|
||||||
}
|
}
|
||||||
@ -828,62 +833,55 @@ public class I2PSnarkServlet extends Default {
|
|||||||
out.write("</td>\n\t");
|
out.write("</td>\n\t");
|
||||||
out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">");
|
out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">");
|
||||||
String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.meta.getInfoHash());
|
String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.meta.getInfoHash());
|
||||||
|
String b64 = Base64.encode(snark.meta.getInfoHash());
|
||||||
if (showPeers)
|
if (showPeers)
|
||||||
parameters = parameters + "&p=1";
|
parameters = parameters + "&p=1";
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
out.write("<a href=\"" + uri + "?action=Stop" + parameters
|
out.write("<input type=\"image\" name=\"action\" value=\"Stop_");
|
||||||
+ "\" title=\"");
|
out.write(b64);
|
||||||
|
out.write("\" title=\"");
|
||||||
out.write(_("Stop the torrent"));
|
out.write(_("Stop the torrent"));
|
||||||
out.write("\">");
|
out.write("\" src=\"/themes/snark/ubergine/images/stop.png\" alt=\"");
|
||||||
out.write("<img src=\"/themes/snark/ubergine/images/stop.png\" title=\"");
|
|
||||||
out.write(_("Stop the torrent"));
|
|
||||||
out.write("\" alt=\"");
|
|
||||||
out.write(_("Stop"));
|
out.write(_("Stop"));
|
||||||
out.write("\">");
|
out.write("\">");
|
||||||
out.write("</a>");
|
|
||||||
} else {
|
} else {
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
out.write("<a href=\"" + uri + "?action=Start" + parameters
|
out.write("<input type=\"image\" name=\"action\" value=\"Start_");
|
||||||
+ "\" title=\"");
|
out.write(b64);
|
||||||
|
out.write("\" title=\"");
|
||||||
out.write(_("Start the torrent"));
|
out.write(_("Start the torrent"));
|
||||||
out.write("\">");
|
out.write("\" src=\"/themes/snark/ubergine/images/start.png\" alt=\"");
|
||||||
out.write("<img src=\"/themes/snark/ubergine/images/start.png\" title=\"");
|
|
||||||
out.write(_("Start the torrent"));
|
|
||||||
out.write("\" alt=\"");
|
|
||||||
out.write(_("Start"));
|
out.write(_("Start"));
|
||||||
out.write("\">");
|
out.write("\">");
|
||||||
out.write("</a>");
|
|
||||||
}
|
}
|
||||||
out.write("<a href=\"" + uri + "?action=Remove" + parameters
|
|
||||||
+ "\" title=\"");
|
out.write("<input type=\"image\" name=\"action\" value=\"Remove_");
|
||||||
|
out.write(b64);
|
||||||
|
out.write("\" title=\"");
|
||||||
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
|
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
|
||||||
out.write("\" onclick=\"if (!confirm('");
|
out.write("\" onclick=\"if (!confirm('");
|
||||||
// Can't figure out how to escape double quotes inside the onclick string.
|
// Can't figure out how to escape double quotes inside the onclick string.
|
||||||
// Single quotes in translate strings with parameters must be doubled.
|
// Single quotes in translate strings with parameters must be doubled.
|
||||||
// Then the remaining single quite must be escaped
|
// Then the remaining single quite must be escaped
|
||||||
out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
|
out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
|
||||||
out.write("')) { return false; }\">");
|
out.write("')) { return false; }\"");
|
||||||
out.write("<img src=\"/themes/snark/ubergine/images/remove.png\" title=\"");
|
out.write(" src=\"/themes/snark/ubergine/images/remove.png\" alt=\"");
|
||||||
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
|
|
||||||
out.write("\" alt=\"");
|
|
||||||
out.write(_("Remove"));
|
out.write(_("Remove"));
|
||||||
out.write("\">");
|
out.write("\">");
|
||||||
out.write("</a>");
|
|
||||||
out.write("<a href=\"" + uri + "?action=Delete" + parameters
|
out.write("<input type=\"image\" name=\"action\" value=\"Delete_");
|
||||||
+ "\" title=\"");
|
out.write(b64);
|
||||||
|
out.write("\" title=\"");
|
||||||
out.write(_("Delete the .torrent file and the associated data file(s)"));
|
out.write(_("Delete the .torrent file and the associated data file(s)"));
|
||||||
out.write("\" onclick=\"if (!confirm('");
|
out.write("\" onclick=\"if (!confirm('");
|
||||||
// Can't figure out how to escape double quotes inside the onclick string.
|
// Can't figure out how to escape double quotes inside the onclick string.
|
||||||
// Single quotes in translate strings with parameters must be doubled.
|
// Single quotes in translate strings with parameters must be doubled.
|
||||||
// Then the remaining single quite must be escaped
|
// Then the remaining single quite must be escaped
|
||||||
out.write(_("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?", fullFilename));
|
out.write(_("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?", fullFilename));
|
||||||
out.write("')) { return false; }\">");
|
out.write("')) { return false; }\"");
|
||||||
out.write("<img src=\"/themes/snark/ubergine/images/delete.png\" title=\"");
|
out.write(" src=\"/themes/snark/ubergine/images/delete.png\" alt=\"");
|
||||||
out.write(_("Delete the .torrent file and the associated data file(s)"));
|
|
||||||
out.write("\" alt=\"");
|
|
||||||
out.write(_("Delete"));
|
out.write(_("Delete"));
|
||||||
out.write("\">");
|
out.write("\">");
|
||||||
out.write("</a>");
|
|
||||||
}
|
}
|
||||||
out.write("</td>\n</tr>\n");
|
out.write("</td>\n</tr>\n");
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public class ConfigPeerHandler extends FormHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addFormError(_("Invalid peer"));
|
addFormError(_("Invalid peer"));
|
||||||
} else if (_action.equals(_("Adjust Profile Bonuses"))) {
|
} else if (_action.equals(_("Adjust peer bonuses"))) {
|
||||||
Hash h = getHash();
|
Hash h = getHash();
|
||||||
if (h != null) {
|
if (h != null) {
|
||||||
PeerProfile prof = _context.profileOrganizer().getProfile(h);
|
PeerProfile prof = _context.profileOrganizer().getProfile(h);
|
||||||
@ -59,6 +59,8 @@ public class ConfigPeerHandler extends FormHandler {
|
|||||||
addFormError(_("Invalid peer"));
|
addFormError(_("Invalid peer"));
|
||||||
} else if (_action.startsWith("Check")) {
|
} else if (_action.startsWith("Check")) {
|
||||||
addFormError(_("Unsupported"));
|
addFormError(_("Unsupported"));
|
||||||
|
} else {
|
||||||
|
addFormError("Unknown action \"" + _action + '"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,26 +20,23 @@ public class FormHandler {
|
|||||||
protected Log _log;
|
protected Log _log;
|
||||||
private String _nonce;
|
private String _nonce;
|
||||||
protected String _action;
|
protected String _action;
|
||||||
|
protected String _method;
|
||||||
protected String _passphrase;
|
protected String _passphrase;
|
||||||
private List<String> _errors;
|
private final List<String> _errors;
|
||||||
private List<String> _notices;
|
private final List<String> _notices;
|
||||||
private boolean _processed;
|
private boolean _processed;
|
||||||
private boolean _valid;
|
private boolean _valid;
|
||||||
|
|
||||||
public FormHandler() {
|
public FormHandler() {
|
||||||
_errors = new ArrayList();
|
_errors = new ArrayList();
|
||||||
_notices = new ArrayList();
|
_notices = new ArrayList();
|
||||||
_action = null;
|
|
||||||
_processed = false;
|
|
||||||
_valid = true;
|
_valid = true;
|
||||||
_nonce = null;
|
|
||||||
_passphrase = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure this bean to query a particular router context
|
* Configure this bean to query a particular router context
|
||||||
*
|
*
|
||||||
* @param contextId begging few characters of the routerHash, or null to pick
|
* @param contextId beginning few characters of the routerHash, or null to pick
|
||||||
* the first one we come across.
|
* the first one we come across.
|
||||||
*/
|
*/
|
||||||
public void setContextId(String contextId) {
|
public void setContextId(String contextId) {
|
||||||
@ -55,6 +52,14 @@ public class FormHandler {
|
|||||||
public void setAction(String val) { _action = val; }
|
public void setAction(String val) { _action = val; }
|
||||||
public void setPassphrase(String val) { _passphrase = val; }
|
public void setPassphrase(String val) { _passphrase = val; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this to prevent changes using GET
|
||||||
|
*
|
||||||
|
* @param the request method
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public void storeMethod(String val) { _method = val; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this to perform the final processing (in turn, adding formNotice
|
* Override this to perform the final processing (in turn, adding formNotice
|
||||||
* and formError messages, etc)
|
* and formError messages, etc)
|
||||||
@ -145,6 +150,12 @@ public class FormHandler {
|
|||||||
_valid = false;
|
_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// To prevent actions with GET, jsps must call storeMethod()
|
||||||
|
if (_method != null && !"POST".equals(_method)) {
|
||||||
|
addFormError("Invalid form submission, requires POST not " + _method);
|
||||||
|
_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String sharedNonce = System.getProperty("router.consoleNonce");
|
String sharedNonce = System.getProperty("router.consoleNonce");
|
||||||
if ( (sharedNonce != null) && (sharedNonce.equals(_nonce) ) ) {
|
if ( (sharedNonce != null) && (sharedNonce.equals(_nonce) ) ) {
|
||||||
@ -211,4 +222,8 @@ public class FormHandler {
|
|||||||
return Messages.getString(s, o, _context);
|
return Messages.getString(s, o, _context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** two params @since 0.8.2 */
|
||||||
|
public String _(String s, Object o, Object o2) {
|
||||||
|
return Messages.getString(s, o, o2, _context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.i2p.router.web;
|
package net.i2p.router.web;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -9,7 +10,8 @@ import java.util.TreeSet;
|
|||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.stat.Rate;
|
import net.i2p.stat.Rate;
|
||||||
|
|
||||||
public class GraphHelper extends HelperBase {
|
public class GraphHelper extends FormHandler {
|
||||||
|
protected Writer _out;
|
||||||
private int _periodCount;
|
private int _periodCount;
|
||||||
private boolean _showEvents;
|
private boolean _showEvents;
|
||||||
private int _width;
|
private int _width;
|
||||||
@ -29,9 +31,6 @@ public class GraphHelper extends HelperBase {
|
|||||||
static final int MAX_Y = 1024;
|
static final int MAX_Y = 1024;
|
||||||
private static final int MIN_REFRESH = 15;
|
private static final int MIN_REFRESH = 15;
|
||||||
|
|
||||||
public GraphHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** set the defaults after we have a context */
|
/** set the defaults after we have a context */
|
||||||
@Override
|
@Override
|
||||||
public void setContextId(String contextId) {
|
public void setContextId(String contextId) {
|
||||||
@ -43,6 +42,12 @@ public class GraphHelper extends HelperBase {
|
|||||||
_showEvents = Boolean.valueOf(_context.getProperty(PROP_EVENTS)).booleanValue();
|
_showEvents = Boolean.valueOf(_context.getProperty(PROP_EVENTS)).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This was a HelperBase but now it's a FormHandler
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public void storeWriter(Writer out) { _out = out; }
|
||||||
|
|
||||||
public void setPeriodCount(String str) {
|
public void setPeriodCount(String str) {
|
||||||
try { _periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
try { _periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {}
|
||||||
}
|
}
|
||||||
@ -125,10 +130,15 @@ public class GraphHelper extends HelperBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getForm() {
|
public String getForm() {
|
||||||
saveSettings();
|
String prev = System.getProperty("net.i2p.router.web.GraphHelper.nonce");
|
||||||
|
if (prev != null) System.setProperty("net.i2p.router.web.GraphHelper.noncePrev", prev);
|
||||||
|
String nonce = "" + _context.random().nextLong();
|
||||||
|
System.setProperty("net.i2p.router.web.GraphHelper.nonce", nonce);
|
||||||
try {
|
try {
|
||||||
_out.write("<br><h3>" + _("Configure Graph Display") + " [<a href=\"configstats\">" + _("Select Stats") + "</a>]</h3>");
|
_out.write("<br><h3>" + _("Configure Graph Display") + " [<a href=\"configstats\">" + _("Select Stats") + "</a>]</h3>");
|
||||||
_out.write("<form action=\"graphs\" method=\"POST\">");
|
_out.write("<form action=\"graphs\" method=\"POST\">\n" +
|
||||||
|
"<input type=\"hidden\" name=\"action\" value=\"foo\">\n" +
|
||||||
|
"<input type=\"hidden\" name=\"nonce\" value=\"" + nonce + "\" >\n");
|
||||||
_out.write(_("Periods") + ": <input size=\"3\" type=\"text\" name=\"periodCount\" value=\"" + _periodCount + "\"><br>\n");
|
_out.write(_("Periods") + ": <input size=\"3\" type=\"text\" name=\"periodCount\" value=\"" + _periodCount + "\"><br>\n");
|
||||||
_out.write(_("Plot averages") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"false\" " + (_showEvents ? "" : "checked=\"true\" ") + "> ");
|
_out.write(_("Plot averages") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"false\" " + (_showEvents ? "" : "checked=\"true\" ") + "> ");
|
||||||
_out.write(_("or")+ " " +_("plot events") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"true\" "+ (_showEvents ? "checked=\"true\" " : "") + "><br>\n");
|
_out.write(_("or")+ " " +_("plot events") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"true\" "+ (_showEvents ? "checked=\"true\" " : "") + "><br>\n");
|
||||||
@ -143,6 +153,15 @@ public class GraphHelper extends HelperBase {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This was a HelperBase but now it's a FormHandler
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void processForm() {
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Silently save settings if changed, no indication of success or failure
|
* Silently save settings if changed, no indication of success or failure
|
||||||
* @since 0.7.10
|
* @since 0.7.10
|
||||||
@ -159,6 +178,7 @@ public class GraphHelper extends HelperBase {
|
|||||||
_context.router().setConfigSetting(PROP_REFRESH, "" + _refreshDelaySeconds);
|
_context.router().setConfigSetting(PROP_REFRESH, "" + _refreshDelaySeconds);
|
||||||
_context.router().setConfigSetting(PROP_EVENTS, "" + _showEvents);
|
_context.router().setConfigSetting(PROP_EVENTS, "" + _showEvents);
|
||||||
_context.router().saveConfig();
|
_context.router().saveConfig();
|
||||||
|
addFormNotice(_("Graph settings saved"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,13 @@ public abstract class HelperBase {
|
|||||||
/** might be useful in the jsp's */
|
/** might be useful in the jsp's */
|
||||||
//public RouterContext getContext() { return _context; }
|
//public RouterContext getContext() { return _context; }
|
||||||
|
|
||||||
public void setWriter(Writer out) { _out = out; }
|
|
||||||
|
/**
|
||||||
|
* Renamed from setWriter, we realy don't want setFoo(non-String)
|
||||||
|
* Prevent jsp.error.beans.property.conversion 500 error for ?writer=foo
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public void storeWriter(Writer out) { _out = out; }
|
||||||
|
|
||||||
/** translate a string */
|
/** translate a string */
|
||||||
public String _(String s) {
|
public String _(String s) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigNetHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigNetHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigAdvancedHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigAdvancedHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -21,6 +21,7 @@ button span.hide{
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigClientsHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigClientsHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="formhandler" property="action" value="<%=request.getParameter("action")%>" />
|
<jsp:setProperty name="formhandler" property="action" value="<%=request.getParameter("action")%>" />
|
||||||
<jsp:setProperty name="formhandler" property="nonce" value="<%=request.getParameter("nonce")%>" />
|
<jsp:setProperty name="formhandler" property="nonce" value="<%=request.getParameter("nonce")%>" />
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigKeyringHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigKeyringHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigLoggingHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigLoggingHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
%>
|
%>
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigNavHelper" id="navHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigNavHelper" id="navHelper" scope="request" />
|
||||||
<jsp:setProperty name="navHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="navHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="navHelper" property="writer" value="<%=out%>" />
|
<% navHelper.storeWriter(out); %>
|
||||||
<div class="confignav" id="confignav">
|
<div class="confignav" id="confignav">
|
||||||
<center>
|
<center>
|
||||||
<%
|
<%
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigPeerHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigPeerHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
@ -27,7 +28,7 @@
|
|||||||
peer = net.i2p.data.DataHelper.stripHTML(request.getParameter("peer")); // XSS
|
peer = net.i2p.data.DataHelper.stripHTML(request.getParameter("peer")); // XSS
|
||||||
%>
|
%>
|
||||||
<div class="configure">
|
<div class="configure">
|
||||||
<form action="" method="POST">
|
<form action="configpeer" method="POST">
|
||||||
<% String prev = System.getProperty("net.i2p.router.web.ConfigPeerHandler.nonce");
|
<% String prev = System.getProperty("net.i2p.router.web.ConfigPeerHandler.nonce");
|
||||||
if (prev != null) System.setProperty("net.i2p.router.web.ConfigPeerHandler.noncePrev", prev);
|
if (prev != null) System.setProperty("net.i2p.router.web.ConfigPeerHandler.noncePrev", prev);
|
||||||
System.setProperty("net.i2p.router.web.ConfigPeerHandler.nonce", new java.util.Random().nextLong()+""); %>
|
System.setProperty("net.i2p.router.web.ConfigPeerHandler.nonce", new java.util.Random().nextLong()+""); %>
|
||||||
@ -64,7 +65,7 @@
|
|||||||
<a name="shitlist"> </a><h2><%=intl._("Banned Peers")%></h2>
|
<a name="shitlist"> </a><h2><%=intl._("Banned Peers")%></h2>
|
||||||
<jsp:useBean class="net.i2p.router.web.ProfilesHelper" id="profilesHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ProfilesHelper" id="profilesHelper" scope="request" />
|
||||||
<jsp:setProperty name="profilesHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="profilesHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="profilesHelper" property="writer" value="<%=out%>" />
|
<% profilesHelper.storeWriter(out); %>
|
||||||
<jsp:getProperty name="profilesHelper" property="shitlistSummary" />
|
<jsp:getProperty name="profilesHelper" property="shitlistSummary" />
|
||||||
<div class="wideload"><h2><%=intl._("Banned IPs")%></h2>
|
<div class="wideload"><h2><%=intl._("Banned IPs")%></h2>
|
||||||
<jsp:getProperty name="peerhelper" property="blocklistSummary" />
|
<jsp:getProperty name="peerhelper" property="blocklistSummary" />
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigServiceHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigServiceHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -58,8 +58,9 @@ function toggleAll(category)
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigStatsHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigStatsHandler" id="formhandler" scope="request" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigStatsHelper" id="statshelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigStatsHelper" id="statshelper" scope="request" />
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<div class="main" id="main">
|
<div class="main" id="main">
|
||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigTunnelsHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigTunnelsHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="formhandler" property="shouldsave" value="<%=request.getParameter("shouldsave")%>" />
|
<jsp:setProperty name="formhandler" property="shouldsave" value="<%=request.getParameter("shouldsave")%>" />
|
||||||
<jsp:setProperty name="formhandler" property="action" value="<%=request.getParameter("action")%>" />
|
<jsp:setProperty name="formhandler" property="action" value="<%=request.getParameter("action")%>" />
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigUIHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigUIHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<%@include file="confignav.jsi" %>
|
<%@include file="confignav.jsi" %>
|
||||||
|
|
||||||
<jsp:useBean class="net.i2p.router.web.ConfigUpdateHandler" id="formhandler" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ConfigUpdateHandler" id="formhandler" scope="request" />
|
||||||
|
<% formhandler.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="formhandler" property="*" />
|
<jsp:setProperty name="formhandler" property="*" />
|
||||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<%@page contentType="text/plain"
|
<%@page contentType="text/plain"
|
||||||
%><jsp:useBean id="helper" class="net.i2p.router.web.StatHelper"
|
%><jsp:useBean id="helper" class="net.i2p.router.web.StatHelper"
|
||||||
/><jsp:setProperty name="helper" property="peer" value="<%=request.getParameter("peer")%>"
|
/><jsp:setProperty name="helper" property="peer" value="<%=request.getParameter("peer")%>"
|
||||||
/><jsp:setProperty name="helper" property="writer" value="<%=out%>"
|
/><% helper.storeWriter(out);
|
||||||
/><jsp:getProperty name="helper" property="profile" />
|
%><jsp:getProperty name="helper" property="profile" />
|
||||||
|
@ -13,9 +13,12 @@
|
|||||||
<div class="graphspanel">
|
<div class="graphspanel">
|
||||||
<div class="widepanel">
|
<div class="widepanel">
|
||||||
<jsp:useBean class="net.i2p.router.web.GraphHelper" id="graphHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.GraphHelper" id="graphHelper" scope="request" />
|
||||||
|
<% graphHelper.storeMethod(request.getMethod()); %>
|
||||||
<jsp:setProperty name="graphHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="graphHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
|
<% /* GraphHelper sets the defaults in setContextId, so setting the properties must be after the context */ %>
|
||||||
<jsp:setProperty name="graphHelper" property="*" />
|
<jsp:setProperty name="graphHelper" property="*" />
|
||||||
<jsp:setProperty name="graphHelper" property="writer" value="<%=out%>" />
|
<% graphHelper.storeWriter(out); %>
|
||||||
|
<jsp:getProperty name="graphHelper" property="allMessages" />
|
||||||
<jsp:getProperty name="graphHelper" property="images" />
|
<jsp:getProperty name="graphHelper" property="images" />
|
||||||
<jsp:getProperty name="graphHelper" property="form" />
|
<jsp:getProperty name="graphHelper" property="form" />
|
||||||
</div></div></div></body></html>
|
</div></div></div></body></html>
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
<meta http-equiv="pragma" content="no-cache" />
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
The I2PSnark Anonymous BitTorrent Client is not running. Please visit the <a href="/configclients.jsp">config clients page</a>
|
The I2PSnark Anonymous BitTorrent Client is not running. Please visit the <a href="/configclients#webapp">config clients page</a>
|
||||||
to start it.
|
to start it.
|
||||||
</body></html>
|
</body></html>
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
<meta http-equiv="pragma" content="no-cache" />
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
The I2P Tunnel Manager is not currently running. Please visit the <a href="/configclients.jsp">Client Configuration</a> page to start it.
|
The I2P Tunnel Manager is not currently running. Please visit the <a href="/configclients#webapp">Client Configuration</a> page to start it.
|
||||||
</body></html>
|
</body></html>
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
<div class="main" id="main">
|
<div class="main" id="main">
|
||||||
<jsp:useBean class="net.i2p.router.web.JobQueueHelper" id="jobQueueHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.JobQueueHelper" id="jobQueueHelper" scope="request" />
|
||||||
<jsp:setProperty name="jobQueueHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="jobQueueHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="jobQueueHelper" property="writer" value="<%=out%>" />
|
<% jobQueueHelper.storeWriter(out); %>
|
||||||
<jsp:getProperty name="jobQueueHelper" property="jobQueueSummary" />
|
<jsp:getProperty name="jobQueueHelper" property="jobQueueSummary" />
|
||||||
<hr></div></body></html>
|
<hr></div></body></html>
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
<h1><%=intl._("I2P Router Logs")%></h1>
|
<h1><%=intl._("I2P Router Logs")%></h1>
|
||||||
<div class="main" id="main">
|
<div class="main" id="main">
|
||||||
<div class="joblog"><h3><%=intl._("I2P Version & Running Environment")%></h3><a name="version"> </a>
|
<div class="joblog"><h3><%=intl._("I2P Version & Running Environment")%></h3><a name="version"> </a>
|
||||||
<p><%=intl._("Please report bugs on <a href=\"http://trac.i2p2.i2p/newticket\">trac.i2p2.i2p</a>.")%>
|
<p><%=intl._("Please report bugs on <a href=\"http://trac.i2p2.i2p/newticket\">trac.i2p2.i2p</a> or <a href=\"http://trac.i2p2.de/newticket\">trac.i2p2.de</a>.")%>
|
||||||
|
<%=intl._("You may use the username \"guest\" and password \"guest\" if you do not wish to register.")%>
|
||||||
<p><i><%=intl._("Please include this information in bug reports")%>:</i>
|
<p><i><%=intl._("Please include this information in bug reports")%>:</i>
|
||||||
<p>
|
<p>
|
||||||
<b>I2P version:</b> <jsp:getProperty name="helper" property="version" /><br>
|
<b>I2P version:</b> <jsp:getProperty name="helper" property="version" /><br>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<div class="wideload">
|
<div class="wideload">
|
||||||
<jsp:useBean class="net.i2p.router.web.NetDbHelper" id="netdbHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.NetDbHelper" id="netdbHelper" scope="request" />
|
||||||
<jsp:setProperty name="netdbHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="netdbHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="netdbHelper" property="writer" value="<%=out%>" />
|
<% netdbHelper.storeWriter(out); %>
|
||||||
<jsp:setProperty name="netdbHelper" property="full" value="<%=request.getParameter("f")%>" />
|
<jsp:setProperty name="netdbHelper" property="full" value="<%=request.getParameter("f")%>" />
|
||||||
<jsp:setProperty name="netdbHelper" property="router" value="<%=request.getParameter("r")%>" />
|
<jsp:setProperty name="netdbHelper" property="router" value="<%=request.getParameter("r")%>" />
|
||||||
<jsp:setProperty name="netdbHelper" property="lease" value="<%=request.getParameter("l")%>" />
|
<jsp:setProperty name="netdbHelper" property="lease" value="<%=request.getParameter("l")%>" />
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<%@include file="summary.jsi" %>
|
<%@include file="summary.jsi" %>
|
||||||
<jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="conhelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="conhelper" scope="request" />
|
||||||
<jsp:setProperty name="conhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="conhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="conhelper" property="writer" value="<%=out%>" />
|
<% conhelper.storeWriter(out); %>
|
||||||
<h1>I2P Router » Old Console</h1>
|
<h1>I2P Router » Old Console</h1>
|
||||||
<div class="main" id="main">
|
<div class="main" id="main">
|
||||||
<jsp:getProperty name="conhelper" property="console" />
|
<jsp:getProperty name="conhelper" property="console" />
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<div class="main" id="main"><div class="wideload">
|
<div class="main" id="main"><div class="wideload">
|
||||||
<jsp:useBean class="net.i2p.router.web.PeerHelper" id="peerHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.PeerHelper" id="peerHelper" scope="request" />
|
||||||
<jsp:setProperty name="peerHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="peerHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="peerHelper" property="writer" value="<%=out%>" />
|
<% peerHelper.storeWriter(out); %>
|
||||||
<jsp:setProperty name="peerHelper" property="urlBase" value="peers.jsp" />
|
<jsp:setProperty name="peerHelper" property="urlBase" value="peers.jsp" />
|
||||||
<jsp:setProperty name="peerHelper" property="sort" value="<%=request.getParameter("sort") != null ? request.getParameter("sort") : ""%>" />
|
<jsp:setProperty name="peerHelper" property="sort" value="<%=request.getParameter("sort") != null ? request.getParameter("sort") : ""%>" />
|
||||||
<jsp:getProperty name="peerHelper" property="peerSummary" />
|
<jsp:getProperty name="peerHelper" property="peerSummary" />
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<div class="main" id="main"><div class="wideload">
|
<div class="main" id="main"><div class="wideload">
|
||||||
<jsp:useBean class="net.i2p.router.web.ProfilesHelper" id="profilesHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.ProfilesHelper" id="profilesHelper" scope="request" />
|
||||||
<jsp:setProperty name="profilesHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="profilesHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="profilesHelper" property="writer" value="<%=out%>" />
|
<% profilesHelper.storeWriter(out); %>
|
||||||
<jsp:setProperty name="profilesHelper" property="full" value="<%=request.getParameter("f")%>" />
|
<jsp:setProperty name="profilesHelper" property="full" value="<%=request.getParameter("f")%>" />
|
||||||
<jsp:getProperty name="profilesHelper" property="profileSummary" />
|
<jsp:getProperty name="profilesHelper" property="profileSummary" />
|
||||||
<a name="shitlist"> </a><h2><%=intl._("Banned Peers")%></h2>
|
<a name="shitlist"> </a><h2><%=intl._("Banned Peers")%></h2>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<%@include file="summary.jsi" %>
|
<%@include file="summary.jsi" %>
|
||||||
<jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="oldhelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.OldConsoleHelper" id="oldhelper" scope="request" />
|
||||||
<jsp:setProperty name="oldhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="oldhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="oldhelper" property="writer" value="<%=out%>" />
|
<% oldhelper.storeWriter(out); %>
|
||||||
<jsp:setProperty name="oldhelper" property="full" value="<%=request.getParameter("f")%>" />
|
<jsp:setProperty name="oldhelper" property="full" value="<%=request.getParameter("f")%>" />
|
||||||
<h1><%=intl._("I2P Router Statistics")%></h1>
|
<h1><%=intl._("I2P Router Statistics")%></h1>
|
||||||
<div class="main" id="main">
|
<div class="main" id="main">
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<jsp:setProperty name="helper" property="updateNonce" value="<%=request.getParameter("updateNonce")%>" />
|
<jsp:setProperty name="helper" property="updateNonce" value="<%=request.getParameter("updateNonce")%>" />
|
||||||
<jsp:setProperty name="helper" property="consoleNonce" value="<%=request.getParameter("consoleNonce")%>" />
|
<jsp:setProperty name="helper" property="consoleNonce" value="<%=request.getParameter("consoleNonce")%>" />
|
||||||
<jsp:setProperty name="helper" property="requestURI" value="<%=request.getRequestURI()%>" />
|
<jsp:setProperty name="helper" property="requestURI" value="<%=request.getRequestURI()%>" />
|
||||||
<jsp:setProperty name="helper" property="writer" value="<%=out%>" />
|
<% helper.storeWriter(out); %>
|
||||||
<%
|
<%
|
||||||
/*
|
/*
|
||||||
* The following is required for the reseed button to work, although we probably
|
* The following is required for the reseed button to work, although we probably
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
<meta http-equiv="pragma" content="no-cache" />
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
SusiDNS is not running. Go to <a href="/configclients.jsp">the config clients page</a>
|
SusiDNS is not running. Go to <a href="/configclients#webapp">the config clients page</a>
|
||||||
to start it.
|
to start it.
|
||||||
</body></html>
|
</body></html>
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
<meta http-equiv="pragma" content="no-cache" />
|
<meta http-equiv="pragma" content="no-cache" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
SusiMail is not running. Go to <a href="/configclients.jsp">the config clients page</a>
|
SusiMail is not running. Go to <a href="/configclients#webapp">the config clients page</a>
|
||||||
to start it.
|
to start it.
|
||||||
</body></html>
|
</body></html>
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
<div class="main" id="main">
|
<div class="main" id="main">
|
||||||
<jsp:useBean class="net.i2p.router.web.TunnelHelper" id="tunnelHelper" scope="request" />
|
<jsp:useBean class="net.i2p.router.web.TunnelHelper" id="tunnelHelper" scope="request" />
|
||||||
<jsp:setProperty name="tunnelHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
<jsp:setProperty name="tunnelHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||||
<jsp:setProperty name="tunnelHelper" property="writer" value="<%=out%>" />
|
<% tunnelHelper.storeWriter(out); %>
|
||||||
<jsp:getProperty name="tunnelHelper" property="tunnelSummary" />
|
<jsp:getProperty name="tunnelHelper" property="tunnelSummary" />
|
||||||
</div></body></html>
|
</div></body></html>
|
||||||
|
@ -98,6 +98,7 @@ public class Connection {
|
|||||||
_log = _context.logManager().getLog(Connection.class);
|
_log = _context.logManager().getLog(Connection.class);
|
||||||
_receiver = new ConnectionDataReceiver(_context, this);
|
_receiver = new ConnectionDataReceiver(_context, this);
|
||||||
_inputStream = new MessageInputStream(_context);
|
_inputStream = new MessageInputStream(_context);
|
||||||
|
// FIXME pass through a passive flush delay setting as the 4th arg
|
||||||
_outputStream = new MessageOutputStream(_context, _receiver, (opts == null ? Packet.MAX_PAYLOAD_SIZE : opts.getMaxMessageSize()));
|
_outputStream = new MessageOutputStream(_context, _receiver, (opts == null ? Packet.MAX_PAYLOAD_SIZE : opts.getMaxMessageSize()));
|
||||||
_outboundPackets = new TreeMap();
|
_outboundPackets = new TreeMap();
|
||||||
_options = (opts != null ? opts : new ConnectionOptions());
|
_options = (opts != null ? opts : new ConnectionOptions());
|
||||||
|
72
build.xml
72
build.xml
@ -245,7 +245,7 @@
|
|||||||
<delete file="debian/substvars"/>
|
<delete file="debian/substvars"/>
|
||||||
</target>
|
</target>
|
||||||
<target name="distclean" depends="clean">
|
<target name="distclean" depends="clean">
|
||||||
<delete includeemptydirs="true" removeNotFollowedSymlinks="true" failonerror="false" >
|
<delete includeemptydirs="true" failonerror="false" >
|
||||||
<fileset dir="debian/packages" followSymlinks="false" />
|
<fileset dir="debian/packages" followSymlinks="false" />
|
||||||
</delete>
|
</delete>
|
||||||
<delete dir="debian/repo" />
|
<delete dir="debian/repo" />
|
||||||
@ -368,7 +368,7 @@
|
|||||||
</copy>
|
</copy>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="preppkg-base" depends="build, preplicenses, prepconsoleDocs">
|
<target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates">
|
||||||
<!-- if updater200 was run previously, it left *.pack files in pkg-temp -->
|
<!-- if updater200 was run previously, it left *.pack files in pkg-temp -->
|
||||||
<delete>
|
<delete>
|
||||||
<fileset dir="pkg-temp" includes="**/*.jar.pack **/*.war.pack" />
|
<fileset dir="pkg-temp" includes="**/*.jar.pack **/*.war.pack" />
|
||||||
@ -419,10 +419,6 @@
|
|||||||
<copy file="installer/resources/start.ico" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/start.ico" todir="pkg-temp/docs/" />
|
||||||
<copy file="installer/resources/console.ico" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/console.ico" todir="pkg-temp/docs/" />
|
||||||
<copy file="installer/resources/uninstall.ico" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/uninstall.ico" todir="pkg-temp/docs/" />
|
||||||
<mkdir dir="pkg-temp/docs/themes/" />
|
|
||||||
<copy todir="pkg-temp/docs/themes/" >
|
|
||||||
<fileset dir="installer/resources/themes/" />
|
|
||||||
</copy>
|
|
||||||
<!-- Eepsite stuff here -->
|
<!-- Eepsite stuff here -->
|
||||||
<mkdir dir="pkg-temp/eepsite" />
|
<mkdir dir="pkg-temp/eepsite" />
|
||||||
<mkdir dir="pkg-temp/eepsite/webapps" />
|
<mkdir dir="pkg-temp/eepsite/webapps" />
|
||||||
@ -455,42 +451,17 @@
|
|||||||
<copy file="installer/lib/launch4j/lib/JGoodies.Looks.LICENSE.txt" tofile="pkg-temp/licenses/LICENSE-JGoodies-Looks.txt" />
|
<copy file="installer/lib/launch4j/lib/JGoodies.Looks.LICENSE.txt" tofile="pkg-temp/licenses/LICENSE-JGoodies-Looks.txt" />
|
||||||
<copy file="installer/lib/launch4j/lib/XStream.LICENSE.txt" tofile="pkg-temp/licenses/LICENSE-XStream.txt" />
|
<copy file="installer/lib/launch4j/lib/XStream.LICENSE.txt" tofile="pkg-temp/licenses/LICENSE-XStream.txt" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="prepthemeupdates">
|
<target name="prepthemeupdates">
|
||||||
<!-- Migrated all Snark content to its own dir. Need to ensure snark dir excluded from console theme choices!! -->
|
<copy todir="pkg-temp/docs/themes/" >
|
||||||
<!-- Snark's visible Assets -->
|
<fileset dir="installer/resources/themes/" />
|
||||||
<copy todir="pkg-temp/docs/themes/snark/ubergine/" >
|
|
||||||
<fileset dir="installer/resources/themes/snark/ubergine/" />
|
|
||||||
</copy>
|
</copy>
|
||||||
<!-- No need to copy these individually, we're copying the whole dir below..
|
</target>
|
||||||
<copy file="installer/resources/themes/console/images/favicon.ico" todir="pkg-temp/docs/themes/console/images/" />
|
|
||||||
<copy file="installer/resources/themes/console/images/i2plogo.png" todir="pkg-temp/docs/themes/console/images/" />
|
<!-- SSL Certs -->
|
||||||
-->
|
<target name="prepCertificates">
|
||||||
<!-- Since the logo moved, we have to update the error pages -->
|
<copy todir="pkg-temp/certificates/" >
|
||||||
<copy todir="pkg-temp/docs/" >
|
<fileset dir="installer/resources/certificates/" />
|
||||||
<fileset dir="installer/resources/proxy" />
|
|
||||||
</copy>
|
|
||||||
<!-- make a "classic" theme -->
|
|
||||||
<copy todir="pkg-temp/docs/themes/console/classic/" >
|
|
||||||
<fileset dir="installer/resources/themes/console/classic/" />
|
|
||||||
</copy>
|
|
||||||
<!-- Add dark theme -->
|
|
||||||
<copy todir="pkg-temp/docs/themes/console/dark/" >
|
|
||||||
<fileset dir="installer/resources/themes/console/dark/" />
|
|
||||||
</copy>
|
|
||||||
<!-- Add light theme -->
|
|
||||||
<copy todir="pkg-temp/docs/themes/console/light/" >
|
|
||||||
<fileset dir="installer/resources/themes/console/light/" />
|
|
||||||
</copy>
|
|
||||||
<!-- Add midnight theme -->
|
|
||||||
<copy todir="pkg-temp/docs/themes/console/midnight/" >
|
|
||||||
<fileset dir="installer/resources/themes/console/midnight/" />
|
|
||||||
</copy>
|
|
||||||
<!-- Add shared images.. these are subject to flux and change! -->
|
|
||||||
<copy todir="pkg-temp/docs/themes/console/images/" >
|
|
||||||
<fileset dir="installer/resources/themes/console/images/" />
|
|
||||||
</copy>
|
|
||||||
<copy todir="pkg-temp/docs/" >
|
|
||||||
<fileset dir="installer/resources/readme/" includes="readme*.html" />
|
|
||||||
</copy>
|
</copy>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@ -500,16 +471,23 @@
|
|||||||
<tarfileset dir="pkg-temp" includes="**/*" prefix="i2p" />
|
<tarfileset dir="pkg-temp" includes="**/*" prefix="i2p" />
|
||||||
</tar>
|
</tar>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="deletepkg-temp">
|
<target name="deletepkg-temp">
|
||||||
<delete dir="pkg-temp" />
|
<delete dir="pkg-temp" />
|
||||||
</target>
|
</target>
|
||||||
<target name="prepconsoleDocs" depends="prepgeoupdate">
|
|
||||||
|
<!-- readme and proxy error page files, GeoIP files, and flag icons -->
|
||||||
|
<target name="prepConsoleDocs" depends="prepConsoleDocUpdates, prepgeoupdate" />
|
||||||
|
|
||||||
|
<!-- readme and proxy error page files -->
|
||||||
|
<target name="prepConsoleDocUpdates">
|
||||||
<copy todir="pkg-temp/docs/" >
|
<copy todir="pkg-temp/docs/" >
|
||||||
<fileset dir="installer/resources/readme/" includes="readme*.html" />
|
<fileset dir="installer/resources/readme/" includes="readme*.html" />
|
||||||
<fileset dir="installer/resources/proxy" />
|
<fileset dir="installer/resources/proxy/" includes="*.ht" />
|
||||||
</copy>
|
</copy>
|
||||||
</target>
|
</target>
|
||||||
<target name="consoleDocs" depends="deletepkg-temp, prepconsoleDocs">
|
|
||||||
|
<target name="consoleDocs" depends="deletepkg-temp, prepConsoleDocs">
|
||||||
<zip destfile="docs.zip" basedir="pkg-temp" whenempty="fail" />
|
<zip destfile="docs.zip" basedir="pkg-temp" whenempty="fail" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@ -560,7 +538,8 @@
|
|||||||
<copy file="core/java/build/i2ptest.jar" todir="pkg-temp/lib" />
|
<copy file="core/java/build/i2ptest.jar" todir="pkg-temp/lib" />
|
||||||
<zip destfile="i2pupdate.zip" basedir="pkg-temp" />
|
<zip destfile="i2pupdate.zip" basedir="pkg-temp" />
|
||||||
</target>
|
</target>
|
||||||
<target name="prepupdate" depends="build2, prepupdateSmall">
|
|
||||||
|
<target name="prepupdate" depends="build2, prepupdateSmall, prepConsoleDocUpdates, prepCertificates">
|
||||||
<copy file="build/BOB.jar" todir="pkg-temp/lib/" />
|
<copy file="build/BOB.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/sam.jar" todir="pkg-temp/lib/" />
|
<copy file="build/sam.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/i2psnark.jar" todir="pkg-temp/lib" />
|
<copy file="build/i2psnark.jar" todir="pkg-temp/lib" />
|
||||||
@ -587,6 +566,7 @@
|
|||||||
<copy file="installer/resources/news.xml" todir="pkg-temp/docs/" />
|
<copy file="installer/resources/news.xml" todir="pkg-temp/docs/" />
|
||||||
-->
|
-->
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="prepupdateSmall" depends="buildSmall, prepupdateRouter, prepthemeupdates">
|
<target name="prepupdateSmall" depends="buildSmall, prepupdateRouter, prepthemeupdates">
|
||||||
<copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
|
<copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/mstreaming.jar" todir="pkg-temp/lib/" />
|
<copy file="build/mstreaming.jar" todir="pkg-temp/lib/" />
|
||||||
@ -601,10 +581,13 @@
|
|||||||
<!-- decapitalized the file in 0.7.8 -->
|
<!-- decapitalized the file in 0.7.8 -->
|
||||||
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
|
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="prepupdateRouter" depends="buildrouter, deletepkg-temp">
|
<target name="prepupdateRouter" depends="buildrouter, deletepkg-temp">
|
||||||
<copy file="build/i2p.jar" todir="pkg-temp/lib/" />
|
<copy file="build/i2p.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/router.jar" todir="pkg-temp/lib/" />
|
<copy file="build/router.jar" todir="pkg-temp/lib/" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<!-- GeoIP files and flag icons -->
|
||||||
<target name="prepgeoupdate">
|
<target name="prepgeoupdate">
|
||||||
<copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
|
<copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
|
||||||
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
|
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
|
||||||
@ -612,6 +595,7 @@
|
|||||||
<fileset dir="installer/resources/icons/flags" />
|
<fileset dir="installer/resources/icons/flags" />
|
||||||
</copy>
|
</copy>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="prepjupdate" depends="prepupdate, buildWEB">
|
<target name="prepjupdate" depends="prepupdate, buildWEB">
|
||||||
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
<copy file="build/jasper-compiler.jar" todir="pkg-temp/lib/" />
|
||||||
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
<copy file="build/jasper-runtime.jar" todir="pkg-temp/lib/" />
|
||||||
|
@ -456,7 +456,7 @@ public class EepGet {
|
|||||||
for (int i = 0; i < _listeners.size(); i++)
|
for (int i = 0; i < _listeners.size(); i++)
|
||||||
_listeners.get(i).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
|
_listeners.get(i).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("ERR: doFetch failed " + ioe);
|
_log.warn("ERR: doFetch failed ", ioe);
|
||||||
if (ioe instanceof MalformedURLException)
|
if (ioe instanceof MalformedURLException)
|
||||||
_keepFetching = false;
|
_keepFetching = false;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1,55 +1,131 @@
|
|||||||
package net.i2p.util;
|
package net.i2p.util;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Contains code from:
|
||||||
|
* http://blogs.sun.com/andreas/resource/InstallCert.java
|
||||||
|
* http://blogs.sun.com/andreas/entry/no_more_unable_to_find
|
||||||
|
*
|
||||||
|
* ===============
|
||||||
|
*
|
||||||
|
* Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of Sun Microsystems nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
import java.security.cert.CertificateExpiredException;
|
||||||
|
import java.security.cert.CertificateNotYetValidException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
// all part of the CA experiment below
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
//import java.io.FileInputStream;
|
import javax.net.ssl.X509TrustManager;
|
||||||
//import java.io.InputStream;
|
|
||||||
//import java.util.Enumeration;
|
|
||||||
//import java.security.KeyStore;
|
|
||||||
//import java.security.GeneralSecurityException;
|
|
||||||
//import java.security.cert.CertificateExpiredException;
|
|
||||||
//import java.security.cert.CertificateNotYetValidException;
|
|
||||||
//import java.security.cert.CertificateFactory;
|
|
||||||
//import java.security.cert.X509Certificate;
|
|
||||||
//import javax.net.ssl.KeyManagerFactory;
|
|
||||||
//import javax.net.ssl.SSLContext;
|
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.data.Base64;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTPS only, non-proxied only, no retries, no min and max size options, no timeout option
|
* HTTPS only, non-proxied only, no retries, no min and max size options, no timeout option
|
||||||
* Fails on 301 or 302 (doesn't follow redirect)
|
* Fails on 301 or 302 (doesn't follow redirect)
|
||||||
* Fails on self-signed certs (must have a valid cert chain)
|
* Fails on bad certs (must have a valid cert chain)
|
||||||
|
* Self-signed certs or CAs not in the JVM key store must be loaded to be trusted.
|
||||||
|
*
|
||||||
|
* Since 0.8.2, loads additional trusted CA certs from $I2P/certificates/ and ~/.i2p/certificates/
|
||||||
*
|
*
|
||||||
* @author zzz
|
* @author zzz
|
||||||
* @since 0.7.10
|
* @since 0.7.10
|
||||||
*/
|
*/
|
||||||
public class SSLEepGet extends EepGet {
|
public class SSLEepGet extends EepGet {
|
||||||
//private static SSLContext _sslContext;
|
/** if true, save cert chain on cert error */
|
||||||
|
private boolean _saveCerts;
|
||||||
|
/** true if called from main(), used for logging */
|
||||||
|
private boolean _commandLine;
|
||||||
|
/** may be null if init failed */
|
||||||
|
private final SSLContext _sslContext;
|
||||||
|
/** may be null if init failed */
|
||||||
|
private SavingTrustManager _stm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A new SSLEepGet with a new SSLState
|
||||||
|
*/
|
||||||
public SSLEepGet(I2PAppContext ctx, OutputStream outputStream, String url) {
|
public SSLEepGet(I2PAppContext ctx, OutputStream outputStream, String url) {
|
||||||
// we're using this constructor:
|
this(ctx, outputStream, url, null);
|
||||||
// public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) {
|
|
||||||
super(ctx, false, null, -1, 0, -1, -1, null, outputStream, url, true, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSLEepGet url
|
* @param state an SSLState retrieved from a previous SSLEepGet with getSSLState(), or null.
|
||||||
* no command line options supported
|
* This makes repeated fetches from the same host MUCH faster,
|
||||||
|
* and prevents repeated key store loads even for different hosts.
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public SSLEepGet(I2PAppContext ctx, OutputStream outputStream, String url, SSLState state) {
|
||||||
|
// we're using this constructor:
|
||||||
|
// public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) {
|
||||||
|
super(ctx, false, null, -1, 0, -1, -1, null, outputStream, url, true, null, null);
|
||||||
|
if (state != null && state.context != null)
|
||||||
|
_sslContext = state.context;
|
||||||
|
else
|
||||||
|
_sslContext = initSSLContext();
|
||||||
|
if (_sslContext == null)
|
||||||
|
_log.error("Failed to initialize custom SSL context, using default context");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSLEepGet https://foo/bar
|
||||||
|
* or to save cert chain:
|
||||||
|
* SSLEepGet -s https://foo/bar
|
||||||
*/
|
*/
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
String url = null;
|
String url = null;
|
||||||
|
boolean saveCerts = false;
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if (args[i].startsWith("-")) {
|
if (args[i].equals("-s")) {
|
||||||
|
saveCerts = true;
|
||||||
|
} else if (args[i].startsWith("-")) {
|
||||||
usage();
|
usage();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -77,93 +153,322 @@ public class SSLEepGet extends EepGet {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******
|
SSLEepGet get = new SSLEepGet(I2PAppContext.getGlobalContext(), out, url);
|
||||||
* This is all an experiment to add a CA cert loaded from a file so we can use
|
if (saveCerts)
|
||||||
* selfsigned certs on our servers.
|
get._saveCerts = true;
|
||||||
* But it's failing.
|
get._commandLine = true;
|
||||||
* Run as java -Djava.security.debug=certpath -Djavax.net.debug=trustmanager -cp $I2P/lib/i2p.jar net.i2p.util.SSLEepGet "$@"
|
|
||||||
* to see the problems. It isn't including the added cert in the Trust Anchor list.
|
|
||||||
******/
|
|
||||||
|
|
||||||
/******
|
|
||||||
String foo = System.getProperty("javax.net.ssl.keyStore");
|
|
||||||
if (foo == null) {
|
|
||||||
File cacerts = new File(System.getProperty("java.home"), "lib/security/cacerts");
|
|
||||||
foo = cacerts.getAbsolutePath();
|
|
||||||
}
|
|
||||||
System.err.println("Location is: " + foo);
|
|
||||||
try {
|
|
||||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
|
||||||
try {
|
|
||||||
InputStream fis = new FileInputStream(foo);
|
|
||||||
ks.load(fis, "changeit".toCharArray());
|
|
||||||
fis.close();
|
|
||||||
} catch (GeneralSecurityException gse) {
|
|
||||||
System.err.println("KS error, no default keys: " + gse);
|
|
||||||
ks.load(null, "changeit".toCharArray());
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
System.err.println("IO error, no default keys: " + ioe);
|
|
||||||
ks.load(null, "changeit".toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
addCert(ks, "cacert");
|
|
||||||
|
|
||||||
for(Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
|
|
||||||
String alias = e.nextElement();
|
|
||||||
System.err.println("Aliases: " + alias + " isCert? " + ks.isCertificateEntry(alias));
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
|
||||||
kmf.init(ks, "".toCharArray());
|
|
||||||
SSLContext sslc = SSLContext.getInstance("SSL");
|
|
||||||
sslc.init(kmf.getKeyManagers(), null, null);
|
|
||||||
_sslContext = sslc;
|
|
||||||
} catch (GeneralSecurityException gse) {
|
|
||||||
System.err.println("KS error: " + gse);
|
|
||||||
return;
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
System.err.println("IO error: " + ioe);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*******/
|
|
||||||
|
|
||||||
EepGet get = new SSLEepGet(I2PAppContext.getGlobalContext(), out, url);
|
|
||||||
get.addStatusListener(get.new CLIStatusListener(1024, 40));
|
get.addStatusListener(get.new CLIStatusListener(1024, 40));
|
||||||
get.fetch(45*1000, -1, 60*1000);
|
get.fetch(45*1000, -1, 60*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void usage() {
|
private static void usage() {
|
||||||
System.err.println("SSLEepGet url");
|
System.err.println("Usage: SSLEepGet https://url");
|
||||||
|
System.err.println("To save unknown certs, use: SSLEepGet -s https://url");
|
||||||
}
|
}
|
||||||
|
|
||||||
/******
|
/**
|
||||||
private static boolean addCert(KeyStore ks, String file) {
|
* Loads certs from location of javax.net.ssl.keyStore property,
|
||||||
|
* else from $JAVA_HOME/lib/security/jssacacerts,
|
||||||
|
* else from $JAVA_HOME/lib/security/cacerts.
|
||||||
|
*
|
||||||
|
* Then adds certs found in the $I2P/certificates/ directory
|
||||||
|
* and in the ~/.i2p/certificates/ directory.
|
||||||
|
*
|
||||||
|
* @return null on failure
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private SSLContext initSSLContext() {
|
||||||
|
KeyStore ks;
|
||||||
|
try {
|
||||||
|
ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
_log.error("Key Store init error", gse);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean success = false;
|
||||||
|
String override = System.getProperty("javax.net.ssl.keyStore");
|
||||||
|
if (override != null)
|
||||||
|
success = loadCerts(new File(override), ks);
|
||||||
|
if (!success)
|
||||||
|
success = loadCerts(new File(System.getProperty("java.home"), "lib/security/jssecacerts"), ks);
|
||||||
|
if (!success)
|
||||||
|
success = loadCerts(new File(System.getProperty("java.home"), "lib/security/cacerts"), ks);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
_log.error("All key store loads failed, will only load local certificates");
|
||||||
|
} else if (_log.shouldLog(Log.INFO)) {
|
||||||
|
int count = 0;
|
||||||
try {
|
try {
|
||||||
InputStream fis = new FileInputStream(file);
|
for(Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
|
||||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
String alias = e.nextElement();
|
||||||
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
|
if (ks.isCertificateEntry(alias))
|
||||||
fis.close();
|
count++;
|
||||||
System.err.println("Adding cert, Issuer: " + cert.getIssuerX500Principal());
|
|
||||||
try {
|
|
||||||
cert.checkValidity();
|
|
||||||
} catch (CertificateExpiredException cee) {
|
|
||||||
System.err.println("Warning - expired cert: " + cee);
|
|
||||||
} catch (CertificateNotYetValidException cnyve) {
|
|
||||||
System.err.println("Warning - not yet valid cert: " + cnyve);
|
|
||||||
}
|
}
|
||||||
// use file name as alias
|
} catch (Exception foo) {}
|
||||||
ks.setCertificateEntry(file, cert);
|
_log.info("Loaded " + count + " default trusted certificates");
|
||||||
} catch (GeneralSecurityException gse) {
|
}
|
||||||
System.err.println("Read cert error: " + gse);
|
|
||||||
return false;
|
File dir = new File(_context.getBaseDir(), "certificates");
|
||||||
} catch (IOException ioe) {
|
int adds = addCerts(dir, ks);
|
||||||
System.err.println("Read cert error: " + ioe);
|
int totalAdds = adds;
|
||||||
return false;
|
if (adds > 0 && _log.shouldLog(Log.INFO))
|
||||||
}
|
_log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||||
|
if (!_context.getBaseDir().getAbsolutePath().equals(_context.getConfigDir().getAbsolutePath())) {
|
||||||
|
dir = new File(_context.getConfigDir(), "certificates");
|
||||||
|
adds = addCerts(dir, ks);
|
||||||
|
totalAdds += adds;
|
||||||
|
if (adds > 0 && _log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
dir = new File(System.getProperty("user.dir"));
|
||||||
|
if (!_context.getBaseDir().getAbsolutePath().equals(dir.getAbsolutePath())) {
|
||||||
|
dir = new File(_context.getConfigDir(), "certificates");
|
||||||
|
adds = addCerts(dir, ks);
|
||||||
|
totalAdds += adds;
|
||||||
|
if (adds > 0 && _log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Loaded total of " + totalAdds + " new trusted certificates");
|
||||||
|
|
||||||
|
try {
|
||||||
|
SSLContext sslc = SSLContext.getInstance("TLS");
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
tmf.init(ks);
|
||||||
|
X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
|
||||||
|
_stm = new SavingTrustManager(defaultTrustManager);
|
||||||
|
sslc.init(null, new TrustManager[] {_stm}, null);
|
||||||
|
return sslc;
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
_log.error("Key Store update error", gse);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all X509 Certs from a key store File into a KeyStore
|
||||||
|
* Note that each call reinitializes the KeyStore
|
||||||
|
*
|
||||||
|
* @return success
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private boolean loadCerts(File file, KeyStore ks) {
|
||||||
|
if (!file.exists())
|
||||||
|
return false;
|
||||||
|
InputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(file);
|
||||||
|
// "changeit" is the default password
|
||||||
|
ks.load(fis, "changeit".toCharArray());
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
_log.error("KeyStore load error, no default keys: " + file.getAbsolutePath(), gse);
|
||||||
|
try {
|
||||||
|
// not clear if null is allowed for password
|
||||||
|
ks.load(null, "changeit".toCharArray());
|
||||||
|
} catch (Exception foo) {}
|
||||||
|
return false;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
_log.error("KeyStore load error, no default keys: " + file.getAbsolutePath(), ioe);
|
||||||
|
try {
|
||||||
|
ks.load(null, "changeit".toCharArray());
|
||||||
|
} catch (Exception foo) {}
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try { if (fis != null) fis.close(); } catch (IOException foo) {}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*******/
|
|
||||||
|
/**
|
||||||
|
* Load all X509 Certs from a directory and add them to the
|
||||||
|
* trusted set of certificates in the key store
|
||||||
|
*
|
||||||
|
* @return number successfully added
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private int addCerts(File dir, KeyStore ks) {
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Looking for X509 Certificates in " + dir.getAbsolutePath());
|
||||||
|
int added = 0;
|
||||||
|
if (dir.exists() && dir.isDirectory()) {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
File f = files[i];
|
||||||
|
if (!f.isFile())
|
||||||
|
continue;
|
||||||
|
// use file name as alias
|
||||||
|
// https://www.sslshopper.com/ssl-converter.html
|
||||||
|
// No idea if all these formats can actually be read by CertificateFactory
|
||||||
|
String alias = f.getName().toLowerCase();
|
||||||
|
if (alias.endsWith(".crt") || alias.endsWith(".pem") || alias.endsWith(".key") ||
|
||||||
|
alias.endsWith(".der") || alias.endsWith(".key") || alias.endsWith(".p7b") ||
|
||||||
|
alias.endsWith(".p7c") || alias.endsWith(".pfx") || alias.endsWith(".p12"))
|
||||||
|
alias = alias.substring(0, alias.length() - 4);
|
||||||
|
boolean success = addCert(f, alias, ks);
|
||||||
|
if (success)
|
||||||
|
added++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an X509 Cert from a file and add it to the
|
||||||
|
* trusted set of certificates in the key store
|
||||||
|
*
|
||||||
|
* @return success
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private boolean addCert(File file, String alias, KeyStore ks) {
|
||||||
|
InputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(file);
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
|
||||||
|
if (_log.shouldLog(Log.INFO)) {
|
||||||
|
_log.info("Read X509 Certificate from " + file.getAbsolutePath() +
|
||||||
|
" Issuer: " + cert.getIssuerX500Principal() +
|
||||||
|
"; Valid From: " + cert.getNotBefore() +
|
||||||
|
" To: " + cert.getNotAfter());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
cert.checkValidity();
|
||||||
|
} catch (CertificateExpiredException cee) {
|
||||||
|
_log.error("Rejecting expired X509 Certificate: " + file.getAbsolutePath(), cee);
|
||||||
|
return false;
|
||||||
|
} catch (CertificateNotYetValidException cnyve) {
|
||||||
|
_log.error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ks.setCertificateEntry(alias, cert);
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal());
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
_log.error("Error reading X509 Certificate: " + file.getAbsolutePath(), gse);
|
||||||
|
return false;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
_log.error("Error reading X509 Certificate: " + file.getAbsolutePath(), ioe);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try { if (fis != null) fis.close(); } catch (IOException foo) {}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From http://blogs.sun.com/andreas/resource/InstallCert.java
|
||||||
|
* This just saves the certificate chain for later inspection.
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private static class SavingTrustManager implements X509TrustManager {
|
||||||
|
private final X509TrustManager tm;
|
||||||
|
private X509Certificate[] chain;
|
||||||
|
|
||||||
|
SavingTrustManager(X509TrustManager tm) {
|
||||||
|
this.tm = tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||||
|
throws CertificateException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||||
|
throws CertificateException {
|
||||||
|
this.chain = chain;
|
||||||
|
tm.checkServerTrusted(chain, authType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modified from http://blogs.sun.com/andreas/resource/InstallCert.java
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private static void saveCerts(String host, SavingTrustManager stm) {
|
||||||
|
X509Certificate[] chain = stm.chain;
|
||||||
|
if (chain == null) {
|
||||||
|
System.out.println("Could not obtain server certificate chain");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int k = 0; k < chain.length; k++) {
|
||||||
|
X509Certificate cert = chain[k];
|
||||||
|
String name = host + '-' + (k + 1) + ".crt";
|
||||||
|
System.out.println("NOTE: Saving untrusted X509 certificate as " + name);
|
||||||
|
System.out.println(" Issuer: " + cert.getIssuerX500Principal());
|
||||||
|
System.out.println(" Valid From: " + cert.getNotBefore());
|
||||||
|
System.out.println(" Valid To: " + cert.getNotAfter());
|
||||||
|
try {
|
||||||
|
cert.checkValidity();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(" WARNING: Certificate is not currently valid, it cannot be used");
|
||||||
|
}
|
||||||
|
saveCert(cert, new File(name));
|
||||||
|
}
|
||||||
|
System.out.println("NOTE: To trust them, copy the certificate file(s) to the certificates directory and rerun without the -s option");
|
||||||
|
System.out.println("NOTE: EepGet failed, certificate error follows:");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int LINE_LENGTH = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modified from:
|
||||||
|
* http://www.exampledepot.com/egs/java.security.cert/ExportCert.html
|
||||||
|
*
|
||||||
|
* This method writes a certificate to a file in base64 format.
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
private static void saveCert(Certificate cert, File file) {
|
||||||
|
OutputStream os = null;
|
||||||
|
try {
|
||||||
|
// Get the encoded form which is suitable for exporting
|
||||||
|
byte[] buf = cert.getEncoded();
|
||||||
|
os = new FileOutputStream(file);
|
||||||
|
PrintWriter wr = new PrintWriter(os);
|
||||||
|
wr.println("-----BEGIN CERTIFICATE-----");
|
||||||
|
String b64 = Base64.encode(buf, true); // true = use standard alphabet
|
||||||
|
for (int i = 0; i < b64.length(); i += LINE_LENGTH) {
|
||||||
|
wr.println(b64.substring(i, Math.min(i + LINE_LENGTH, b64.length())));
|
||||||
|
}
|
||||||
|
wr.println("-----END CERTIFICATE-----");
|
||||||
|
wr.flush();
|
||||||
|
} catch (CertificateEncodingException cee) {
|
||||||
|
System.out.println("Error writing X509 Certificate " + file.getAbsolutePath() + ' ' + cee);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
System.out.println("Error writing X509 Certificate " + file.getAbsolutePath() + ' ' + ioe);
|
||||||
|
} finally {
|
||||||
|
try { if (os != null) os.close(); } catch (IOException foo) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An opaque class for the caller to pass to repeated instantiations of SSLEepGet.
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public static class SSLState {
|
||||||
|
private SSLContext context;
|
||||||
|
|
||||||
|
private SSLState(SSLContext ctx) {
|
||||||
|
context = ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass this back to the next SSLEepGet constructor for faster fetches.
|
||||||
|
* This may be called either after the constructor or after the fetch.
|
||||||
|
* @since 0.8.2
|
||||||
|
*/
|
||||||
|
public SSLState getSSLState() {
|
||||||
|
return new SSLState(_sslContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
///// end of all the SSL stuff
|
||||||
|
///// start of overrides
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFetch(SocketTimeout timeout) throws IOException {
|
protected void doFetch(SocketTimeout timeout) throws IOException {
|
||||||
@ -288,15 +593,16 @@ public class SSLEepGet extends EepGet {
|
|||||||
|
|
||||||
//try {
|
//try {
|
||||||
URL url = new URL(_actualURL);
|
URL url = new URL(_actualURL);
|
||||||
|
String host = null;
|
||||||
|
int port = 0;
|
||||||
if ("https".equals(url.getProtocol())) {
|
if ("https".equals(url.getProtocol())) {
|
||||||
String host = url.getHost();
|
host = url.getHost();
|
||||||
int port = url.getPort();
|
port = url.getPort();
|
||||||
if (port == -1)
|
if (port == -1)
|
||||||
port = 443;
|
port = 443;
|
||||||
// part of the experiment above
|
if (_sslContext != null)
|
||||||
//if (_sslContext != null)
|
_proxy = _sslContext.getSocketFactory().createSocket(host, port);
|
||||||
// _proxy = _sslContext.getSocketFactory().createSocket(host, port);
|
else
|
||||||
//else
|
|
||||||
_proxy = SSLSocketFactory.getDefault().createSocket(host, port);
|
_proxy = SSLSocketFactory.getDefault().createSocket(host, port);
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("Only https supported: " + _actualURL);
|
throw new IOException("Only https supported: " + _actualURL);
|
||||||
@ -309,8 +615,23 @@ public class SSLEepGet extends EepGet {
|
|||||||
_proxyIn = _proxy.getInputStream();
|
_proxyIn = _proxy.getInputStream();
|
||||||
_proxyOut = _proxy.getOutputStream();
|
_proxyOut = _proxy.getOutputStream();
|
||||||
|
|
||||||
_proxyOut.write(DataHelper.getUTF8(req));
|
// This is where the cert errors happen
|
||||||
_proxyOut.flush();
|
try {
|
||||||
|
_proxyOut.write(DataHelper.getUTF8(req));
|
||||||
|
_proxyOut.flush();
|
||||||
|
} catch (SSLHandshakeException sslhe) {
|
||||||
|
// this maybe would be better done in the catch in super.fetch(), but
|
||||||
|
// then we'd have to copy it all over here.
|
||||||
|
_log.error("SSL negotiation error with " + host + ':' + port +
|
||||||
|
" - self-signed certificate or untrusted certificate authority?", sslhe);
|
||||||
|
if (_saveCerts && _stm != null)
|
||||||
|
saveCerts(host, _stm);
|
||||||
|
else if (_commandLine) {
|
||||||
|
System.out.println("FAILED (probably due to untrusted certificates) - Run with -s option to save certificates");
|
||||||
|
}
|
||||||
|
// this is an IOE
|
||||||
|
throw sslhe;
|
||||||
|
}
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Request flushed");
|
_log.debug("Request flushed");
|
||||||
|
23
history.txt
23
history.txt
@ -1,3 +1,26 @@
|
|||||||
|
2010-11-22 zzz
|
||||||
|
* Addressbook: Fix rename error on Windows (tkt 323 - thanks RN!)
|
||||||
|
* build.xml: Cleanup, fix distclean error in older ants.
|
||||||
|
* Console:
|
||||||
|
- Convert GraphHelper to a FormHandler
|
||||||
|
- Require POST for all forms
|
||||||
|
- Change the way we store the Writer to prevent problems
|
||||||
|
- Fix bonus setting on configpeer.jsp
|
||||||
|
- More ".jsp" removal
|
||||||
|
* i2psnark:
|
||||||
|
- Defer piece loading until required
|
||||||
|
- Stub out Extension message support
|
||||||
|
- Convert GET to POST, require POST
|
||||||
|
* NTCP: Log tweak
|
||||||
|
* SSLEepGet, Reseeder:
|
||||||
|
- Implement additional CA loading
|
||||||
|
- Provide facility to reuse SSL state for speed
|
||||||
|
- Provide facility to store previously untrusted certificates
|
||||||
|
- Add www.cacert.org cert to the installer and updater so
|
||||||
|
SSL on a.netdb.i2p2.de and c.netdb.i2p2.de will work
|
||||||
|
- Add SSL reseed hosts, prefer them by default
|
||||||
|
- Reseed message cleanup
|
||||||
|
|
||||||
2010-11-19 zzz
|
2010-11-19 zzz
|
||||||
* Addressbook
|
* Addressbook
|
||||||
- Store last-fetched time so we don't always fetch subscriptions after restart
|
- Store last-fetched time so we don't always fetch subscriptions after restart
|
||||||
|
41
installer/resources/certificates/www.cacert.org.crt
Normal file
41
installer/resources/certificates/www.cacert.org.crt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
|
||||||
|
IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
|
||||||
|
IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
|
||||||
|
Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
|
||||||
|
BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
|
||||||
|
MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
|
||||||
|
ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||||
|
CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
|
||||||
|
8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
|
||||||
|
zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
|
||||||
|
fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
|
||||||
|
w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
|
||||||
|
G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
|
||||||
|
epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
|
||||||
|
laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
|
||||||
|
QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
|
||||||
|
fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
|
||||||
|
YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
|
||||||
|
ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
|
||||||
|
gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
|
||||||
|
MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
|
||||||
|
IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
|
||||||
|
dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
|
||||||
|
czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
|
||||||
|
dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
|
||||||
|
aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
|
||||||
|
AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
|
||||||
|
b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
|
||||||
|
ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
|
||||||
|
nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
|
||||||
|
18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
|
||||||
|
gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
|
||||||
|
Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
|
||||||
|
sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
|
||||||
|
SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
|
||||||
|
CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
|
||||||
|
GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
|
||||||
|
zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
|
||||||
|
omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
|
||||||
|
-----END CERTIFICATE-----
|
@ -474,6 +474,20 @@ input[type=submit]:active {
|
|||||||
text-shadow: 0 !important;
|
text-shadow: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=image] {
|
||||||
|
padding: 0 !important;
|
||||||
|
background: #000;
|
||||||
|
-moz-border-radius: 0px;
|
||||||
|
-khtml-border-radius: 0px;
|
||||||
|
border-radius: 0px;
|
||||||
|
border: medium none;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=image]:hover {
|
||||||
|
border: 1px outset #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
input[type=text]:active, input[type=text]:hover, input.r:hover {
|
input[type=text]:active, input[type=text]:hover, input.r:hover {
|
||||||
background: #f60;
|
background: #f60;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
29
licenses/LICENSE-InstallCert.txt
Normal file
29
licenses/LICENSE-InstallCert.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
- Neither the name of Sun Microsystems nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 3;
|
public final static long BUILD = 4;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
@ -29,6 +29,8 @@ import net.i2p.util.Translate;
|
|||||||
* specified below unless the I2P configuration property "i2p.reseedURL" is
|
* specified below unless the I2P configuration property "i2p.reseedURL" is
|
||||||
* set. It always writes to ./netDb/, so don't mess with that.
|
* set. It always writes to ./netDb/, so don't mess with that.
|
||||||
*
|
*
|
||||||
|
* This is somewhat complicated by trying to log to three places - the console,
|
||||||
|
* the router log, and the wrapper log.
|
||||||
*/
|
*/
|
||||||
public class Reseeder {
|
public class Reseeder {
|
||||||
private static ReseedRunner _reseedRunner;
|
private static ReseedRunner _reseedRunner;
|
||||||
@ -40,12 +42,25 @@ public class Reseeder {
|
|||||||
|
|
||||||
private static final String DEFAULT_SEED_URL =
|
private static final String DEFAULT_SEED_URL =
|
||||||
"http://a.netdb.i2p2.de/,http://b.netdb.i2p2.de/,http://c.netdb.i2p2.de/," +
|
"http://a.netdb.i2p2.de/,http://b.netdb.i2p2.de/,http://c.netdb.i2p2.de/," +
|
||||||
"http://reseed.i2p-projekt.de/,http://i2pbote.net/netDb/,http://r31453.ovh.net/static_media/netDb/";
|
"http://reseed.i2p-projekt.de/,http://www.i2pbote.net/netDb/,http://r31453.ovh.net/static_media/netDb/";
|
||||||
|
|
||||||
|
/** @since 0.8.2 */
|
||||||
|
private static final String DEFAULT_SSL_SEED_URL =
|
||||||
|
"https://a.netdb.i2p2.de/,https://c.netdb.i2p2.de/," +
|
||||||
|
"https://www.i2pbote.net/netDb/";
|
||||||
|
|
||||||
private static final String PROP_INPROGRESS = "net.i2p.router.web.ReseedHandler.reseedInProgress";
|
private static final String PROP_INPROGRESS = "net.i2p.router.web.ReseedHandler.reseedInProgress";
|
||||||
|
/** the console shows this message while reseedInProgress == false */
|
||||||
private static final String PROP_ERROR = "net.i2p.router.web.ReseedHandler.errorMessage";
|
private static final String PROP_ERROR = "net.i2p.router.web.ReseedHandler.errorMessage";
|
||||||
|
/** the console shows this message while reseedInProgress == true */
|
||||||
private static final String PROP_STATUS = "net.i2p.router.web.ReseedHandler.statusMessage";
|
private static final String PROP_STATUS = "net.i2p.router.web.ReseedHandler.statusMessage";
|
||||||
public static final String PROP_PROXY_HOST = "router.reseedProxyHost";
|
public static final String PROP_PROXY_HOST = "router.reseedProxyHost";
|
||||||
public static final String PROP_PROXY_PORT = "router.reseedProxyPort";
|
public static final String PROP_PROXY_PORT = "router.reseedProxyPort";
|
||||||
|
/** @since 0.8.2 */
|
||||||
|
public static final String PROP_PROXY_ENABLE = "router.reseedProxyEnable";
|
||||||
|
/** @since 0.8.2 */
|
||||||
|
public static final String PROP_SSL_DISABLE = "router.reseedSSLDisable";
|
||||||
|
|
||||||
private static final String RESEED_TIPS =
|
private static final String RESEED_TIPS =
|
||||||
_x("Ensure that nothing blocks outbound HTTP, check <a target=\"_top\" href=\"logs.jsp\">logs</a> " +
|
_x("Ensure that nothing blocks outbound HTTP, check <a target=\"_top\" href=\"logs.jsp\">logs</a> " +
|
||||||
"and if nothing helps, read the <a target=\"_top\" href=\"http://www.i2p2.de/faq.html\">FAQ</a> about reseeding manually.");
|
"and if nothing helps, read the <a target=\"_top\" href=\"http://www.i2p2.de/faq.html\">FAQ</a> about reseeding manually.");
|
||||||
@ -63,7 +78,6 @@ public class Reseeder {
|
|||||||
if (_reseedRunner.isRunning()) {
|
if (_reseedRunner.isRunning()) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
System.setProperty(PROP_INPROGRESS, "true");
|
|
||||||
// set to daemon so it doesn't hang a shutdown
|
// set to daemon so it doesn't hang a shutdown
|
||||||
Thread reseed = new I2PAppThread(_reseedRunner, "Reseed", true);
|
Thread reseed = new I2PAppThread(_reseedRunner, "Reseed", true);
|
||||||
reseed.start();
|
reseed.start();
|
||||||
@ -76,20 +90,46 @@ public class Reseeder {
|
|||||||
private boolean _isRunning;
|
private boolean _isRunning;
|
||||||
private String _proxyHost;
|
private String _proxyHost;
|
||||||
private int _proxyPort;
|
private int _proxyPort;
|
||||||
|
private SSLEepGet.SSLState _sslState;
|
||||||
|
|
||||||
public ReseedRunner() {
|
public ReseedRunner() {
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
|
System.clearProperty(PROP_ERROR);
|
||||||
System.setProperty(PROP_STATUS, _("Reseeding"));
|
System.setProperty(PROP_STATUS, _("Reseeding"));
|
||||||
|
System.setProperty(PROP_INPROGRESS, "true");
|
||||||
}
|
}
|
||||||
public boolean isRunning() { return _isRunning; }
|
public boolean isRunning() { return _isRunning; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do it.
|
||||||
|
* We update PROP_ERROR here.
|
||||||
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
_isRunning = true;
|
_isRunning = true;
|
||||||
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
|
_sslState = null; // start fresh
|
||||||
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
|
if (_context.getBooleanProperty(PROP_PROXY_ENABLE)) {
|
||||||
|
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
|
||||||
|
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
|
||||||
|
}
|
||||||
System.out.println("Reseed start");
|
System.out.println("Reseed start");
|
||||||
reseed(false);
|
int total = reseed(false);
|
||||||
System.out.println("Reseed complete");
|
if (total >= 50) {
|
||||||
|
System.out.println("Reseed complete, " + total + " received");
|
||||||
|
System.clearProperty(PROP_ERROR);
|
||||||
|
} else if (total > 0) {
|
||||||
|
System.out.println("Reseed complete, only " + total + " received");
|
||||||
|
System.setProperty(PROP_ERROR, ngettext("Reseed fetched only 1 router.",
|
||||||
|
"Reseed fetched only {0} routers.", total));
|
||||||
|
} else {
|
||||||
|
System.out.println("Reseed failed, check network connection");
|
||||||
|
System.out.println(
|
||||||
|
"Ensure that nothing blocks outbound HTTP, check the logs, " +
|
||||||
|
"and if nothing helps, read the FAQ about reseeding manually.");
|
||||||
|
System.setProperty(PROP_ERROR, _("Reseed failed.") + ' ' + _(RESEED_TIPS));
|
||||||
|
}
|
||||||
System.setProperty(PROP_INPROGRESS, "false");
|
System.setProperty(PROP_INPROGRESS, "false");
|
||||||
|
System.clearProperty(PROP_STATUS);
|
||||||
|
_sslState = null; // don't hold ref
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,16 +152,56 @@ public class Reseeder {
|
|||||||
* the routerInfo-*.dat files from the specified URL (or the default) and
|
* the routerInfo-*.dat files from the specified URL (or the default) and
|
||||||
* save them into this router's netDb dir.
|
* save them into this router's netDb dir.
|
||||||
*
|
*
|
||||||
|
* - If list specified in the properties, use it randomly, without regard to http/https
|
||||||
|
* - If SSL not disabled, use the https randomly then
|
||||||
|
* the http randomly
|
||||||
|
* - Otherwise just the http randomly.
|
||||||
|
*
|
||||||
|
* @param echoStatus apparently always false
|
||||||
|
* @return count of routerinfos successfully fetched
|
||||||
*/
|
*/
|
||||||
private void reseed(boolean echoStatus) {
|
private int reseed(boolean echoStatus) {
|
||||||
List URLList = new ArrayList();
|
List<String> URLList = new ArrayList();
|
||||||
String URLs = _context.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
String URLs = _context.getProperty("i2p.reseedURL");
|
||||||
|
boolean defaulted = URLs == null;
|
||||||
|
boolean SSLDisable = _context.getBooleanProperty(PROP_SSL_DISABLE);
|
||||||
|
if (defaulted) {
|
||||||
|
if (SSLDisable)
|
||||||
|
URLs = DEFAULT_SEED_URL;
|
||||||
|
else
|
||||||
|
URLs = DEFAULT_SSL_SEED_URL;
|
||||||
|
}
|
||||||
StringTokenizer tok = new StringTokenizer(URLs, " ,");
|
StringTokenizer tok = new StringTokenizer(URLs, " ,");
|
||||||
while (tok.hasMoreTokens())
|
while (tok.hasMoreTokens())
|
||||||
URLList.add(tok.nextToken().trim());
|
URLList.add(tok.nextToken().trim());
|
||||||
Collections.shuffle(URLList);
|
Collections.shuffle(URLList);
|
||||||
for (int i = 0; i < URLList.size() && _isRunning; i++)
|
if (defaulted && !SSLDisable) {
|
||||||
reseedOne((String) URLList.get(i), echoStatus);
|
// put the non-SSL at the end of the SSL
|
||||||
|
List<String> URLList2 = new ArrayList();
|
||||||
|
tok = new StringTokenizer(DEFAULT_SSL_SEED_URL, " ,");
|
||||||
|
while (tok.hasMoreTokens())
|
||||||
|
URLList2.add(tok.nextToken().trim());
|
||||||
|
Collections.shuffle(URLList2);
|
||||||
|
URLList.addAll(URLList2);
|
||||||
|
}
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < URLList.size() && _isRunning; i++) {
|
||||||
|
String url = URLList.get(i);
|
||||||
|
int dl = reseedOne(url, echoStatus);
|
||||||
|
if (dl > 0) {
|
||||||
|
total += dl;
|
||||||
|
// remove alternate version if we haven't tried it yet
|
||||||
|
String alt;
|
||||||
|
if (url.startsWith("http://"))
|
||||||
|
alt = url.replace("http://", "https://");
|
||||||
|
else
|
||||||
|
alt = url.replace("https://", "http://");
|
||||||
|
int idx = URLList.indexOf(alt);
|
||||||
|
if (idx > i)
|
||||||
|
URLList.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,22 +218,23 @@ public class Reseeder {
|
|||||||
*
|
*
|
||||||
* Jetty directory listings are not compatible, as they look like
|
* Jetty directory listings are not compatible, as they look like
|
||||||
* HREF="/full/path/to/routerInfo-...
|
* HREF="/full/path/to/routerInfo-...
|
||||||
|
*
|
||||||
|
* We update PROP_STATUS here.
|
||||||
|
*
|
||||||
|
* @param echoStatus apparently always false
|
||||||
|
* @return count of routerinfos successfully fetched
|
||||||
**/
|
**/
|
||||||
private void reseedOne(String seedURL, boolean echoStatus) {
|
private int reseedOne(String seedURL, boolean echoStatus) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
System.setProperty(PROP_ERROR, "");
|
|
||||||
System.setProperty(PROP_STATUS, _("Reseeding: fetching seed URL."));
|
System.setProperty(PROP_STATUS, _("Reseeding: fetching seed URL."));
|
||||||
System.err.println("Reseed from " + seedURL);
|
System.err.println("Reseeding from " + seedURL);
|
||||||
URL dir = new URL(seedURL);
|
URL dir = new URL(seedURL);
|
||||||
byte contentRaw[] = readURL(dir);
|
byte contentRaw[] = readURL(dir);
|
||||||
if (contentRaw == null) {
|
if (contentRaw == null) {
|
||||||
System.setProperty(PROP_ERROR,
|
|
||||||
_("Last reseed failed fully (failed reading seed URL).") + ' ' +
|
|
||||||
_(RESEED_TIPS));
|
|
||||||
// Logging deprecated here since attemptFailed() provides better info
|
// Logging deprecated here since attemptFailed() provides better info
|
||||||
_log.debug("Failed reading seed URL: " + seedURL);
|
_log.warn("Failed reading seed URL: " + seedURL);
|
||||||
return;
|
System.err.println("Reseed got no router infos from " + seedURL);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
String content = new String(contentRaw);
|
String content = new String(contentRaw);
|
||||||
Set<String> urls = new HashSet(1024);
|
Set<String> urls = new HashSet(1024);
|
||||||
@ -173,11 +254,9 @@ public class Reseeder {
|
|||||||
cur = end + 1;
|
cur = end + 1;
|
||||||
}
|
}
|
||||||
if (total <= 0) {
|
if (total <= 0) {
|
||||||
_log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
|
_log.warn("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
|
||||||
System.setProperty(PROP_ERROR,
|
System.err.println("Reseed got no router infos from " + seedURL);
|
||||||
_("Last reseed failed fully (no routerInfo URLs at seed URL).") + ' ' +
|
return 0;
|
||||||
_(RESEED_TIPS));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> urlList = new ArrayList(urls);
|
List<String> urlList = new ArrayList(urls);
|
||||||
@ -201,32 +280,18 @@ public class Reseeder {
|
|||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.err.println("Reseed got " + fetched + " router infos from " + seedURL);
|
System.err.println("Reseed got " + fetched + " router infos from " + seedURL + " with " + errors + " errors");
|
||||||
|
|
||||||
int failPercent = 100 * errors / total;
|
|
||||||
|
|
||||||
// Less than 10% of failures is considered success,
|
|
||||||
// because some routerInfos will always fail.
|
|
||||||
if ((failPercent >= 10) && (failPercent < 90)) {
|
|
||||||
System.setProperty(PROP_ERROR,
|
|
||||||
_("Last reseed failed partly ({0}% of {1}).", failPercent, total) + ' ' +
|
|
||||||
_(RESEED_TIPS));
|
|
||||||
}
|
|
||||||
if (failPercent >= 90) {
|
|
||||||
System.setProperty(PROP_ERROR,
|
|
||||||
_("Last reseed failed ({0}% of {1}).", failPercent, total) + ' ' +
|
|
||||||
_(RESEED_TIPS));
|
|
||||||
}
|
|
||||||
if (fetched > 0)
|
if (fetched > 0)
|
||||||
_context.netDb().rescan();
|
_context.netDb().rescan();
|
||||||
// Don't go on to the next URL if we have enough
|
// Don't go on to the next URL if we have enough
|
||||||
if (fetched >= 100)
|
if (fetched >= 100)
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
|
return fetched;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
System.setProperty(PROP_ERROR,
|
_log.warn("Error reseeding", t);
|
||||||
_("Last reseed failed fully (exception caught).") + ' ' +
|
System.err.println("Reseed got no router infos from " + seedURL);
|
||||||
_(RESEED_TIPS));
|
return 0;
|
||||||
_log.error("Error reseeding", t);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,8 +313,17 @@ public class Reseeder {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
||||||
|
|
||||||
EepGet get;
|
EepGet get;
|
||||||
if (url.toString().startsWith("https")) {
|
boolean ssl = url.toString().startsWith("https");
|
||||||
get = new SSLEepGet(I2PAppContext.getGlobalContext(), baos, url.toString());
|
if (ssl) {
|
||||||
|
SSLEepGet sslget;
|
||||||
|
if (_sslState == null) {
|
||||||
|
sslget = new SSLEepGet(I2PAppContext.getGlobalContext(), baos, url.toString());
|
||||||
|
// save state for next time
|
||||||
|
_sslState = sslget.getSSLState();
|
||||||
|
} else {
|
||||||
|
sslget = new SSLEepGet(I2PAppContext.getGlobalContext(), baos, url.toString(), _sslState);
|
||||||
|
}
|
||||||
|
get = sslget;
|
||||||
} else {
|
} else {
|
||||||
// Do a (probably) non-proxied eepget into our ByteArrayOutputStream with 0 retries
|
// Do a (probably) non-proxied eepget into our ByteArrayOutputStream with 0 retries
|
||||||
boolean shouldProxy = _proxyHost != null && _proxyHost.length() > 0 && _proxyPort > 0;
|
boolean shouldProxy = _proxyHost != null && _proxyHost.length() > 0 && _proxyPort > 0;
|
||||||
@ -257,7 +331,9 @@ public class Reseeder {
|
|||||||
null, baos, url.toString(), false, null, null);
|
null, baos, url.toString(), false, null, null);
|
||||||
}
|
}
|
||||||
get.addStatusListener(ReseedRunner.this);
|
get.addStatusListener(ReseedRunner.this);
|
||||||
if (get.fetch()) return baos.toByteArray(); else return null;
|
if (get.fetch())
|
||||||
|
return baos.toByteArray();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeSeed(String name, byte data[]) throws Exception {
|
private void writeSeed(String name, byte data[]) throws Exception {
|
||||||
@ -295,6 +371,11 @@ public class Reseeder {
|
|||||||
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** translate */
|
||||||
|
private String ngettext(String s, String p, int n) {
|
||||||
|
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
/******
|
/******
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
if ( (args != null) && (args.length == 1) && (!Boolean.valueOf(args[0]).booleanValue()) ) {
|
if ( (args != null) && (args.length == 1) && (!Boolean.valueOf(args[0]).booleanValue()) ) {
|
||||||
|
@ -1274,10 +1274,10 @@ public class NTCPConnection implements FIFOBandwidthLimiter.CompleteListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.ERROR))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.error("CRC incorrect for message " + _messagesRead + " (calc=" + val + " expected=" + _expectedCrc + ") size=" + _size + " blocks " + _blocks);
|
_log.warn("CRC incorrect for message " + _messagesRead + " (calc=" + val + " expected=" + _expectedCrc + ") size=" + _size + " blocks " + _blocks);
|
||||||
_context.statManager().addRateData("ntcp.corruptI2NPCRC", 1, getUptime());
|
_context.statManager().addRateData("ntcp.corruptI2NPCRC", 1, getUptime());
|
||||||
// should we try to read in the message and keep going?
|
// FIXME should we try to read in the message and keep going?
|
||||||
close();
|
close();
|
||||||
// databuf is lost
|
// databuf is lost
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user