forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head e606c473eb1e461a477e45419f6295b6430a7353)
to branch 'i2p.i2p.zzz.test2' (head 6212892778308db10a86e58f9f275c838f604973)
This commit is contained in:
@@ -54,8 +54,15 @@ public interface CompleteListener {
|
||||
*/
|
||||
public void gotPiece(Snark snark);
|
||||
|
||||
// not really listeners but the easiest way to get back to an optional SnarkManager
|
||||
/** not really listeners but the easiest way to get back to an optional SnarkManager */
|
||||
public long getSavedTorrentTime(Snark snark);
|
||||
public BitField getSavedTorrentBitField(Snark snark);
|
||||
/**
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public boolean getSavedPreserveNamesSetting(Snark snark);
|
||||
/**
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public long getSavedUploaded(Snark snark);
|
||||
}
|
||||
|
@@ -281,6 +281,14 @@ class PeerCoordinator implements PeerListener
|
||||
return uploaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial total of uploaded bytes of all peers (from a saved status)
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public void setUploaded(long up) {
|
||||
uploaded = up;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of downloaded bytes of all peers.
|
||||
*/
|
||||
|
@@ -237,6 +237,7 @@ public class Snark
|
||||
private volatile boolean _autoStoppable;
|
||||
// String indicating main activity
|
||||
private volatile String activity = "Not started";
|
||||
private final long savedUploaded;
|
||||
|
||||
|
||||
/**
|
||||
@@ -463,6 +464,7 @@ public class Snark
|
||||
trackerclient = new TrackerClient(meta, coordinator);
|
||||
*/
|
||||
|
||||
savedUploaded = (completeListener != null) ? completeListener.getSavedUploaded(this) : 0;
|
||||
if (start)
|
||||
startTorrent();
|
||||
}
|
||||
@@ -488,6 +490,7 @@ public class Snark
|
||||
this.infoHash = ih;
|
||||
this.additionalTrackerURL = trackerURL;
|
||||
this.rootDataDir = rootDir != null ? new File(rootDir) : null; // null only for FetchAndAdd extension
|
||||
savedUploaded = 0;
|
||||
stopped = true;
|
||||
id = generateID();
|
||||
|
||||
@@ -556,6 +559,7 @@ public class Snark
|
||||
_log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
|
||||
coordinator.setUploaded(savedUploaded);
|
||||
if (_peerCoordinatorSet != null) {
|
||||
// multitorrent
|
||||
_peerCoordinatorSet.add(coordinator);
|
||||
@@ -619,7 +623,7 @@ public class Snark
|
||||
pc.halt();
|
||||
Storage st = storage;
|
||||
if (st != null) {
|
||||
boolean changed = storage.isChanged();
|
||||
boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
|
||||
try {
|
||||
storage.close();
|
||||
} catch (IOException ioe) {
|
||||
@@ -773,7 +777,7 @@ public class Snark
|
||||
PeerCoordinator coord = coordinator;
|
||||
if (coord != null)
|
||||
return coord.getUploaded();
|
||||
return 0;
|
||||
return savedUploaded;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -92,6 +92,7 @@ public class SnarkManager implements CompleteListener {
|
||||
private static final String PROP_META_BITFIELD = "bitfield";
|
||||
private static final String PROP_META_PRIORITY = "priority";
|
||||
private static final String PROP_META_PRESERVE_NAMES = "preserveFileNames";
|
||||
private static final String PROP_META_UPLOADED = "uploaded";
|
||||
//private static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
|
||||
//private static final String PROP_META_PRIORITY_SUFFIX = ".priority";
|
||||
private static final String PROP_META_MAGNET_PREFIX = "i2psnark.magnet.";
|
||||
@@ -128,6 +129,9 @@ public class SnarkManager implements CompleteListener {
|
||||
/**
|
||||
* "name", "announceURL=websiteURL" pairs
|
||||
* '=' in announceURL must be escaped as ,
|
||||
*
|
||||
* Please use host name, not b32 or full dest, in announce URL. Ensure in default hosts.txt.
|
||||
* Please use host name, not b32 or full dest, in website URL. Ensure in default hosts.txt.
|
||||
*/
|
||||
private static final String DEFAULT_TRACKERS[] = {
|
||||
// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
|
||||
@@ -1357,7 +1361,7 @@ public class SnarkManager implements CompleteListener {
|
||||
return false;
|
||||
}
|
||||
// so addTorrent won't recheck
|
||||
saveTorrentStatus(metainfo, bitfield, null, baseFile, true); // no file priorities
|
||||
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0); // no file priorities
|
||||
try {
|
||||
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
|
||||
// hold the lock for a long time
|
||||
@@ -1522,6 +1526,21 @@ public class SnarkManager implements CompleteListener {
|
||||
Properties config = getConfig(snark);
|
||||
return Boolean.parseBoolean(config.getProperty(PROP_META_PRESERVE_NAMES));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get setting for a torrent from the config file.
|
||||
* @return setting, 0 if not found
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public long getSavedUploaded(Snark snark) {
|
||||
Properties config = getConfig(snark);
|
||||
if (config != null) {
|
||||
try {
|
||||
return Long.parseLong(config.getProperty(PROP_META_UPLOADED));
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the completion status of a torrent and other data in the config file
|
||||
@@ -1535,7 +1554,8 @@ public class SnarkManager implements CompleteListener {
|
||||
if (meta == null || storage == null)
|
||||
return;
|
||||
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
|
||||
storage.getBase(), storage.getPreserveFileNames());
|
||||
storage.getBase(), storage.getPreserveFileNames(),
|
||||
snark.getUploaded());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1550,14 +1570,14 @@ public class SnarkManager implements CompleteListener {
|
||||
* @param base may be null
|
||||
*/
|
||||
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
|
||||
File base, boolean preserveNames) {
|
||||
File base, boolean preserveNames, long uploaded) {
|
||||
synchronized (_configLock) {
|
||||
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames);
|
||||
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames, uploaded);
|
||||
}
|
||||
}
|
||||
|
||||
private void locked_saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
|
||||
File base, boolean preserveNames) {
|
||||
File base, boolean preserveNames, long uploaded) {
|
||||
byte[] ih = metainfo.getInfoHash();
|
||||
String bfs;
|
||||
if (bitfield.complete()) {
|
||||
@@ -1570,6 +1590,7 @@ public class SnarkManager implements CompleteListener {
|
||||
config.setProperty(PROP_META_STAMP, Long.toString(System.currentTimeMillis()));
|
||||
config.setProperty(PROP_META_BITFIELD, bfs);
|
||||
config.setProperty(PROP_META_PRESERVE_NAMES, Boolean.toString(preserveNames));
|
||||
config.setProperty(PROP_META_UPLOADED, Long.toString(uploaded));
|
||||
if (base != null)
|
||||
config.setProperty(PROP_META_BASE, base.getAbsolutePath());
|
||||
|
||||
@@ -1826,7 +1847,7 @@ public class SnarkManager implements CompleteListener {
|
||||
Storage storage = snark.getStorage();
|
||||
if (meta != null && storage != null)
|
||||
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
|
||||
storage.getBase(), storage.getPreserveFileNames());
|
||||
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1849,7 +1870,7 @@ public class SnarkManager implements CompleteListener {
|
||||
return null;
|
||||
}
|
||||
saveTorrentStatus(meta, storage.getBitField(), null,
|
||||
storage.getBase(), storage.getPreserveFileNames()); // no file priorities
|
||||
storage.getBase(), storage.getPreserveFileNames(), 0);
|
||||
// temp for addMessage() in case canonical throws
|
||||
String name = storage.getBaseName();
|
||||
try {
|
||||
|
@@ -316,15 +316,34 @@ public class Storage
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index to pass to remaining(), getPriority(), setPriority()
|
||||
*
|
||||
* @param file non-canonical path (non-directory)
|
||||
* @return internal index of file; -1 if unknown file
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public int indexOf(File file) {
|
||||
for (int i = 0; i < _torrentFiles.size(); i++) {
|
||||
File f = _torrentFiles.get(i).RAFfile;
|
||||
if (f.equals(file))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileIndex as obtained from indexOf
|
||||
* @return number of bytes remaining; -1 if unknown file
|
||||
* @since 0.7.14
|
||||
*/
|
||||
public long remaining(File file) {
|
||||
public long remaining(int fileIndex) {
|
||||
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
|
||||
return -1;
|
||||
long bytes = 0;
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
File f = tf.RAFfile;
|
||||
if (f.equals(file)) {
|
||||
for (int i = 0; i < _torrentFiles.size(); i++) {
|
||||
TorrentFile tf = _torrentFiles.get(i);
|
||||
if (i == fileIndex) {
|
||||
File f = tf.RAFfile;
|
||||
if (complete())
|
||||
return 0;
|
||||
int psz = piece_size;
|
||||
@@ -350,37 +369,30 @@ public class Storage
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file non-canonical path (non-directory)
|
||||
* @param fileIndex as obtained from indexOf
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public int getPriority(File file) {
|
||||
public int getPriority(int fileIndex) {
|
||||
if (complete() || metainfo.getFiles() == null)
|
||||
return 0;
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
File f = tf.RAFfile;
|
||||
if (f.equals(file))
|
||||
return tf.priority;
|
||||
}
|
||||
return 0;
|
||||
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
|
||||
return 0;
|
||||
return _torrentFiles.get(fileIndex).priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must call Snark.updatePiecePriorities()
|
||||
* (which calls getPiecePriorities()) after calling this.
|
||||
* @param file non-canonical path (non-directory)
|
||||
* @param fileIndex as obtained from indexOf
|
||||
* @param pri default 0; <0 to disable
|
||||
* @since 0.8.1
|
||||
*/
|
||||
public void setPriority(File file, int pri) {
|
||||
public void setPriority(int fileIndex, int pri) {
|
||||
if (complete() || metainfo.getFiles() == null)
|
||||
return;
|
||||
for (TorrentFile tf : _torrentFiles) {
|
||||
File f = tf.RAFfile;
|
||||
if (f.equals(file)) {
|
||||
tf.priority = pri;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
|
||||
return;
|
||||
_torrentFiles.get(fileIndex).priority = pri;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -72,6 +72,8 @@ public class TrackerClient implements Runnable {
|
||||
private static final String STOPPED_EVENT = "stopped";
|
||||
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
|
||||
private static final String NOT_REGISTERED_2 = "torrent not found"; // diftracker
|
||||
private static final String NOT_REGISTERED_3 = "torrent unauthorised"; // vuze
|
||||
private static final String ERROR_GOT_HTML = "received html"; // fake return
|
||||
/** this is our equivalent to router.utorrent.com for bootstrap */
|
||||
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
|
||||
|
||||
@@ -577,14 +579,20 @@ public class TrackerClient implements Runnable {
|
||||
if (tr.isPrimary)
|
||||
snark.setTrackerProblems(tr.trackerProblems);
|
||||
String tplc = tr.trackerProblems.toLowerCase(Locale.US);
|
||||
if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2)) {
|
||||
if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2) ||
|
||||
tplc.startsWith(NOT_REGISTERED_3) || tplc.startsWith(ERROR_GOT_HTML)) {
|
||||
// Give a guy some time to register it if using opentrackers too
|
||||
//if (trckrs.size() == 1) {
|
||||
// stop = true;
|
||||
// snark.stopTorrent();
|
||||
//} else { // hopefully each on the opentrackers list is really open
|
||||
if (tr.registerFails++ > MAX_REGISTER_FAILS ||
|
||||
!completed || // no use retrying if we aren't seeding
|
||||
tplc.startsWith(ERROR_GOT_HTML) || // fake msg from doRequest()
|
||||
(!tr.isPrimary && tr.registerFails > MAX_REGISTER_FAILS / 2))
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Not longer announcing to " + tr.announce + " : " +
|
||||
tr.trackerProblems + " after " + tr.registerFails + " failures");
|
||||
tr.stop = true;
|
||||
//
|
||||
}
|
||||
@@ -797,10 +805,15 @@ public class TrackerClient implements Runnable {
|
||||
tr.lastRequestTime = System.currentTimeMillis();
|
||||
// Don't wait for a response to stopped when shutting down
|
||||
boolean fast = _fastUnannounce && event.equals(STOPPED_EVENT);
|
||||
byte[] fetched = _util.get(s, true, fast ? -1 : 0, small ? 128 : 1024, small ? 1024 : 8*1024);
|
||||
if (fetched == null) {
|
||||
throw new IOException("Error fetching " + s);
|
||||
}
|
||||
byte[] fetched = _util.get(s, true, fast ? -1 : 0, small ? 128 : 1024, small ? 1024 : 32*1024);
|
||||
if (fetched == null)
|
||||
throw new IOException("Error fetching");
|
||||
if (fetched.length == 0)
|
||||
throw new IOException("No data");
|
||||
// The HTML check only works if we didn't exceed the maxium fetch size specified in get(),
|
||||
// otherwise we already threw an IOE.
|
||||
if (fetched[0] == '<')
|
||||
throw new IOException(ERROR_GOT_HTML);
|
||||
|
||||
InputStream in = new ByteArrayInputStream(fetched);
|
||||
|
||||
|
@@ -295,6 +295,10 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
return _smgr.getSavedPreserveNamesSetting(snark);
|
||||
}
|
||||
|
||||
public long getSavedUploaded(Snark snark) {
|
||||
return _smgr.getSavedUploaded(snark);
|
||||
}
|
||||
|
||||
//////// end CompleteListener methods
|
||||
|
||||
private static String linkify(String url) {
|
||||
|
@@ -25,8 +25,10 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.klomp.snark.I2PSnarkUtil;
|
||||
@@ -498,7 +500,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write(_("RX"));
|
||||
out.write("\">");
|
||||
out.write("</th>\n<th align=\"right\">");
|
||||
if (_manager.util().connected() && !snarks.isEmpty()) {
|
||||
if (!snarks.isEmpty()) {
|
||||
out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" title=\"");
|
||||
out.write(_("Uploaded"));
|
||||
out.write("\" alt=\"");
|
||||
@@ -1430,8 +1432,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write("</td><td class=\"snarkTorrentName\"");
|
||||
if (isMultiFile) {
|
||||
// link on the whole td
|
||||
String jsec = encodedBaseName.replace("'", "\\'");
|
||||
out.write(" onclick=\"document.location='" + jsec + "/';\">");
|
||||
out.write(" onclick=\"document.location='" + encodedBaseName + "/';\">");
|
||||
} else {
|
||||
out.write('>');
|
||||
}
|
||||
@@ -1465,15 +1466,15 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
// out.write("??"); // no meta size yet
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td align=\"right\" class=\"snarkTorrentUploaded\">");
|
||||
if(isRunning && isValid)
|
||||
if (isValid && uploaded > 0)
|
||||
out.write(formatSize(uploaded));
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
|
||||
if(isRunning && needed > 0)
|
||||
if (isRunning && needed > 0)
|
||||
out.write(formatSize(downBps) + "ps");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
|
||||
if(isRunning && isValid)
|
||||
if (isRunning && isValid)
|
||||
out.write(formatSize(upBps) + "ps");
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td align=\"center\" class=\"snarkTorrentAction\">");
|
||||
@@ -1717,8 +1718,10 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start of anchor only, caller must add anchor text or img and close anchor
|
||||
* @return string or null
|
||||
* Generate link to details page if we know it supports it.
|
||||
* Start of anchor only, caller must add anchor text or img and close anchor.
|
||||
*
|
||||
* @return string or null if unknown tracker
|
||||
* @since 0.8.4
|
||||
*/
|
||||
private String getTrackerLinkUrl(String announce, byte[] infohash) {
|
||||
@@ -1745,8 +1748,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Full anchor with img
|
||||
* @return string or null
|
||||
* Full link to details page with img
|
||||
* @return string or null if details page unsupported
|
||||
* @since 0.8.4
|
||||
*/
|
||||
private String getTrackerLink(String announce, byte[] infohash) {
|
||||
@@ -1762,7 +1765,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Full anchor with shortened URL as anchor text
|
||||
* Full anchor to home page or details page with shortened host name as anchor text
|
||||
* @return string, non-null
|
||||
* @since 0.9.5
|
||||
*/
|
||||
@@ -1771,14 +1774,37 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
String trackerLinkUrl = getTrackerLinkUrl(announce, infohash);
|
||||
if (announce.startsWith("http://"))
|
||||
announce = announce.substring(7);
|
||||
// strip path
|
||||
int slsh = announce.indexOf('/');
|
||||
if (slsh > 0)
|
||||
announce = announce.substring(0, slsh);
|
||||
if (trackerLinkUrl != null)
|
||||
if (trackerLinkUrl != null) {
|
||||
buf.append(trackerLinkUrl);
|
||||
else
|
||||
// TODO encode
|
||||
buf.append("<a href=\"http://").append(urlEncode(announce)).append("/\">");
|
||||
} else {
|
||||
// browsers don't like a full b64 dest, so convert it to b32
|
||||
String host = announce;
|
||||
if (host.length() >= 516) {
|
||||
int colon = announce.indexOf(':');
|
||||
String port = "";
|
||||
if (colon > 0) {
|
||||
port = host.substring(colon);
|
||||
host = host.substring(0, colon);
|
||||
}
|
||||
if (host.endsWith(".i2p"))
|
||||
host = host.substring(0, host.length() - 4);
|
||||
byte[] b = Base64.decode(host);
|
||||
if (b != null) {
|
||||
Hash h = _context.sha().calculateHash(b);
|
||||
// should we add the port back or strip it?
|
||||
host = Base32.encode(h.getData()) + ".b32.i2p" + port;
|
||||
}
|
||||
}
|
||||
buf.append("<a href=\"http://").append(urlEncode(host)).append("/\">");
|
||||
}
|
||||
// strip port
|
||||
int colon = announce.indexOf(':');
|
||||
if (colon > 0)
|
||||
announce = announce.substring(0, colon);
|
||||
if (announce.length() > 67)
|
||||
announce = DataHelper.escapeHTML(announce.substring(0, 40)) + "…" +
|
||||
DataHelper.escapeHTML(announce.substring(announce.length() - 8));
|
||||
@@ -2673,6 +2699,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
boolean complete = false;
|
||||
String status = "";
|
||||
long length = item.length();
|
||||
int fileIndex = -1;
|
||||
int priority = 0;
|
||||
if (item.isDirectory()) {
|
||||
complete = true;
|
||||
@@ -2684,8 +2711,9 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
status = toImg("cancel") + ' ' + _("Torrent not found?");
|
||||
} else {
|
||||
Storage storage = snark.getStorage();
|
||||
fileIndex = storage.indexOf(item);
|
||||
|
||||
long remaining = storage.remaining(item);
|
||||
long remaining = storage.remaining(fileIndex);
|
||||
if (remaining < 0) {
|
||||
complete = true;
|
||||
status = toImg("cancel") + ' ' + _("File not found in torrent?");
|
||||
@@ -2693,7 +2721,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
complete = true;
|
||||
status = toImg("tick") + ' ' + _("Complete");
|
||||
} else {
|
||||
priority = storage.getPriority(item);
|
||||
priority = storage.getPriority(fileIndex);
|
||||
if (priority < 0)
|
||||
status = toImg("cancel");
|
||||
else if (priority == 0)
|
||||
@@ -2745,17 +2773,17 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (showPriority) {
|
||||
buf.append("<td class=\"priority\">");
|
||||
if ((!complete) && (!item.isDirectory())) {
|
||||
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(item).append("\" ");
|
||||
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
|
||||
if (priority > 0)
|
||||
buf.append("checked=\"checked\"");
|
||||
buf.append('>').append(_("High"));
|
||||
|
||||
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(item).append("\" ");
|
||||
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
|
||||
if (priority == 0)
|
||||
buf.append("checked=\"checked\"");
|
||||
buf.append('>').append(_("Normal"));
|
||||
|
||||
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(item).append("\" ");
|
||||
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
|
||||
if (priority < 0)
|
||||
buf.append("checked=\"checked\"");
|
||||
buf.append('>').append(_("Skip"));
|
||||
@@ -2857,10 +2885,10 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
String key = entry.getKey();
|
||||
if (key.startsWith("pri.")) {
|
||||
try {
|
||||
File file = new File(key.substring(4));
|
||||
int fileIndex = Integer.parseInt(key.substring(4));
|
||||
String val = entry.getValue()[0]; // jetty arrays
|
||||
int pri = Integer.parseInt(val);
|
||||
storage.setPriority(file, pri);
|
||||
storage.setPriority(fileIndex, pri);
|
||||
//System.err.println("Priority now " + pri + " for " + file);
|
||||
} catch (Throwable t) { t.printStackTrace(); }
|
||||
}
|
||||
|
@@ -84,6 +84,7 @@ class URIUtil
|
||||
case '<':
|
||||
case '>':
|
||||
case ' ':
|
||||
case ':':
|
||||
buf=new StringBuilder(path.length()*2);
|
||||
break loop;
|
||||
default:
|
||||
@@ -139,6 +140,9 @@ class URIUtil
|
||||
case 0x7f:
|
||||
buf.append("%7F");
|
||||
continue;
|
||||
case ':':
|
||||
buf.append("%3A");
|
||||
continue;
|
||||
default:
|
||||
if (c <= 0x1f) // includes negative
|
||||
toHex(c,buf);
|
||||
@@ -183,6 +187,9 @@ class URIUtil
|
||||
case ' ':
|
||||
buf.append("%20");
|
||||
continue;
|
||||
case ':':
|
||||
buf.append("%3A");
|
||||
continue;
|
||||
default:
|
||||
if (c <= 0x1f || (c >= 0x7f && c <= 0x9f) || Character.isSpaceChar(c))
|
||||
toHex(c,buf);
|
||||
|
@@ -182,6 +182,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
if (getTunnel() != tunnel)
|
||||
return;
|
||||
setupPostThrottle();
|
||||
Properties props = tunnel.getClientOptions();
|
||||
// see TunnelController.setSessionOptions()
|
||||
String spoofHost = props.getProperty(TunnelController.PROP_SPOOFED_HOST);
|
||||
_spoofHost = (spoofHost != null && spoofHost.trim().length() > 0) ? spoofHost.trim() : null;
|
||||
super.optionsUpdated(tunnel);
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -50,8 +51,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
protected final Object slock = new Object();
|
||||
protected final Object sslLock = new Object();
|
||||
|
||||
protected final InetAddress remoteHost;
|
||||
protected final int remotePort;
|
||||
protected InetAddress remoteHost;
|
||||
protected int remotePort;
|
||||
private final boolean _usePool;
|
||||
protected final Logging l;
|
||||
private I2PSSLSocketFactory _sslFactory;
|
||||
@@ -265,6 +266,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
* Copy input stream to a byte array, so we can retry
|
||||
* @since 0.7.10
|
||||
*/
|
||||
/****
|
||||
private static ByteArrayInputStream copyOfInputStream(InputStream is) throws IOException {
|
||||
byte[] buf = new byte[128];
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(768);
|
||||
@@ -279,6 +281,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
}
|
||||
return new ByteArrayInputStream(os.toByteArray());
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Start running the I2PTunnelServer.
|
||||
@@ -348,6 +351,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
/**
|
||||
* Update the I2PSocketManager.
|
||||
* And since 0.9.15, the target host and port.
|
||||
*
|
||||
* @since 0.9.1
|
||||
*/
|
||||
@@ -357,6 +361,27 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
return;
|
||||
Properties props = tunnel.getClientOptions();
|
||||
sockMgr.setDefaultOptions(sockMgr.buildOptions(props));
|
||||
// see TunnelController.setSessionOptions()
|
||||
String h = props.getProperty(TunnelController.PROP_TARGET_HOST);
|
||||
if (h != null) {
|
||||
try {
|
||||
remoteHost = InetAddress.getByName(h);
|
||||
} catch (UnknownHostException uhe) {
|
||||
l.log("Unknown host: " + h);
|
||||
}
|
||||
}
|
||||
String p = props.getProperty(TunnelController.PROP_TARGET_PORT);
|
||||
if (p != null) {
|
||||
try {
|
||||
int port = Integer.parseInt(p);
|
||||
if (port > 0 && port <= 65535)
|
||||
remotePort = port;
|
||||
else
|
||||
l.log("Bad port: " + port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("Bad port: " + p);
|
||||
}
|
||||
}
|
||||
buildSocketMap(props);
|
||||
}
|
||||
|
||||
|
@@ -487,6 +487,17 @@ public class TunnelController implements Logging {
|
||||
String proxies = getProxyList();
|
||||
if (proxies != null)
|
||||
opts.setProperty(PROP_PROXIES, proxies);
|
||||
// Ditto spoof host. Since 0.9.15.
|
||||
String spoofhost = getSpoofedHost();
|
||||
if (spoofhost != null)
|
||||
opts.setProperty(PROP_SPOOFED_HOST, spoofhost);
|
||||
// Ditto target host/port. Since 0.9.15.
|
||||
String targethost = getTargetHost();
|
||||
if (targethost != null)
|
||||
opts.setProperty(PROP_TARGET_HOST, targethost);
|
||||
String targetport = getTargetPort();
|
||||
if (targetport != null)
|
||||
opts.setProperty(PROP_TARGET_PORT, targetport);
|
||||
_tunnel.setClientOptions(opts);
|
||||
}
|
||||
|
||||
|
@@ -258,6 +258,7 @@ public class IndexBean {
|
||||
// give the messages a chance to make it to the window
|
||||
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
|
||||
// and give them something to look at in any case
|
||||
// FIXME name will be HTML escaped twice
|
||||
return _("Starting tunnel") + ' ' + getTunnelName(_tunnel) + "...";
|
||||
}
|
||||
|
||||
@@ -271,6 +272,7 @@ public class IndexBean {
|
||||
// give the messages a chance to make it to the window
|
||||
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
|
||||
// and give them something to look at in any case
|
||||
// FIXME name will be HTML escaped twice
|
||||
return _("Stopping tunnel") + ' ' + getTunnelName(_tunnel) + "...";
|
||||
}
|
||||
|
||||
@@ -352,6 +354,7 @@ public class IndexBean {
|
||||
List<String> msgs = doSave();
|
||||
if (ksMsg != null)
|
||||
msgs.add(ksMsg);
|
||||
// FIXME name will be HTML escaped twice
|
||||
return getMessages(msgs);
|
||||
}
|
||||
|
||||
@@ -402,7 +405,8 @@ public class IndexBean {
|
||||
name = Long.toString(_context.clock().now());
|
||||
}
|
||||
}
|
||||
name = "i2ptunnel-deleted-" + name.replace(' ', '_') + '-' + _context.clock().now() + "-privkeys.dat";
|
||||
name = name.replace(' ', '_').replace(':', '_').replace("..", "_").replace('/', '_').replace('\\', '_');
|
||||
name = "i2ptunnel-deleted-" + name + '-' + _context.clock().now() + "-privkeys.dat";
|
||||
File backupDir = new SecureFile(_context.getConfigDir(), TunnelController.KEY_BACKUP_DIR);
|
||||
File to;
|
||||
if (backupDir.isDirectory() || backupDir.mkdir())
|
||||
@@ -451,13 +455,11 @@ public class IndexBean {
|
||||
}
|
||||
|
||||
public boolean allowCSS() {
|
||||
String css = _context.getProperty(PROP_CSS_DISABLED);
|
||||
return (css == null);
|
||||
return !_context.getBooleanProperty(PROP_CSS_DISABLED);
|
||||
}
|
||||
|
||||
public boolean allowJS() {
|
||||
String js = _context.getProperty(PROP_JS_DISABLED);
|
||||
return (js == null);
|
||||
return !_context.getBooleanProperty(PROP_JS_DISABLED);
|
||||
}
|
||||
|
||||
public int getTunnelCount() {
|
||||
@@ -727,8 +729,9 @@ public class IndexBean {
|
||||
_name = (name != null ? name.trim() : null);
|
||||
}
|
||||
/** one line description */
|
||||
public void setDescription(String description) {
|
||||
_description = (description != null ? description.trim() : null);
|
||||
public void setNofilter_description(String description) {
|
||||
// '#' will blow up DataHelper.storeProps()
|
||||
_description = (description != null ? description.replace('#', ' ').trim() : null);
|
||||
}
|
||||
/** I2CP host the router is on, ignored when in router context */
|
||||
public void setClientHost(String host) {
|
||||
|
@@ -79,7 +79,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
<label for="description" accesskey="e">
|
||||
<%=intl._("Description")%>:(<span class="accessKey">E</span>)
|
||||
</label>
|
||||
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
|
||||
<input type="text" size="60" maxlength="80" name="nofilter_description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
@@ -341,6 +341,23 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label for="reduce" accesskey="c">
|
||||
<%=intl._("Delay tunnel open until required")%>(<span class="accessKey">D</span>):
|
||||
</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="access" accesskey="c">
|
||||
<%=intl._("Enable")%>:
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="delayOpen" title="Delay Tunnel Open"<%=(editBean.getDelayOpen(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
</div>
|
||||
<% } // !streamrclient %>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label for="reduce" accesskey="d">
|
||||
@@ -405,23 +422,6 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label for="reduce" accesskey="c">
|
||||
<%=intl._("Delay tunnel open until required")%>(<span class="accessKey">D</span>):
|
||||
</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="access" accesskey="c">
|
||||
<%=intl._("Enable")%>:
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="delayOpen" title="Delay Tunnel Open"<%=(editBean.getDelayOpen(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
</div>
|
||||
<% } // !streamrclient %>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<% if ("client".equals(tunnelType) || "ircclient".equals(tunnelType) || "socksirctunnel".equals(tunnelType) || "sockstunnel".equals(tunnelType)) { %>
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label for="privKeyFile" accesskey="k">
|
||||
|
@@ -79,7 +79,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
<label for="description" accesskey="e">
|
||||
<%=intl._("Description")%>(<span class="accessKey">e</span>):
|
||||
</label>
|
||||
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
|
||||
<input type="text" size="60" maxlength="80" name="nofilter_description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="startupField" class="rowItem">
|
||||
<label for="startOnLoad" accesskey="a">
|
||||
|
@@ -233,11 +233,11 @@
|
||||
<label for="description" accesskey="e">
|
||||
<%=intl._("Description")%>:(<span class="accessKey">E</span>)
|
||||
</label>
|
||||
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=(!"null".equals(request.getParameter("description")) ? net.i2p.data.DataHelper.stripHTML(request.getParameter("description")) : "" ) %>" class="freetext" />
|
||||
<input type="text" size="60" maxlength="80" name="nofilter_description" id="description" title="Tunnel Description" value="<%=(!"null".equals(request.getParameter("description")) ? net.i2p.data.DataHelper.stripHTML(request.getParameter("description")) : "" ) %>" class="freetext" />
|
||||
</div><%
|
||||
} else {
|
||||
%><input type="hidden" name="name" value="<%=net.i2p.data.DataHelper.stripHTML(request.getParameter("name"))%>" />
|
||||
<input type="hidden" name="description" value="<%=net.i2p.data.DataHelper.stripHTML(request.getParameter("description"))%>" /><%
|
||||
<input type="hidden" name="nofilter_description" value="<%=net.i2p.data.DataHelper.stripHTML(request.getParameter("description"))%>" /><%
|
||||
} /* curPage 3 */
|
||||
|
||||
/* End page 3 */ %>
|
||||
@@ -484,7 +484,7 @@
|
||||
<input type="hidden" name="tunnelBackupQuantity" value="0" />
|
||||
<input type="hidden" name="clientHost" value="internal" />
|
||||
<input type="hidden" name="clientport" value="internal" />
|
||||
<input type="hidden" name="customOptions" value="" />
|
||||
<input type="hidden" name="nofilter_customOptions" value="" />
|
||||
|
||||
<%
|
||||
if (!"streamrclient".equals(tunnelType)) {
|
||||
@@ -501,9 +501,9 @@
|
||||
}
|
||||
if ("httpclient".equals(tunnelType) || "connectclient".equals(tunnelType) || "sockstunnel".equals(tunnelType) || "socksirctunnel".equals(tunnelType)) {
|
||||
%><input type="hidden" name="proxyUsername" value="" />
|
||||
<input type="hidden" name="proxyPassword" value="" />
|
||||
<input type="hidden" name="nofilter_proxyPassword" value="" />
|
||||
<input type="hidden" name="outproxyUsername" value="" />
|
||||
<input type="hidden" name="outproxyPassword" value="" /><%
|
||||
<input type="hidden" name="nofilter_outproxyPassword" value="" /><%
|
||||
}
|
||||
if ("httpclient".equals(tunnelType)) {
|
||||
%><input type="hidden" name="jumpList" value="http://i2host.i2p/cgi-bin/i2hostjump?
|
||||
|
@@ -158,6 +158,8 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
||||
// right at instantiation if the news is already indicating a new version
|
||||
Checker c = new NewsHandler(_context, this);
|
||||
register(c, NEWS, HTTP, 0);
|
||||
// TODO
|
||||
//register(c, NEWS_SU3, HTTP, 0);
|
||||
register(c, ROUTER_SIGNED, HTTP, 0); // news is an update checker for the router
|
||||
Updater u = new UpdateHandler(_context, this);
|
||||
register(u, ROUTER_SIGNED, HTTP, 0);
|
||||
@@ -734,9 +736,9 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
||||
UpdateType type, String id,
|
||||
Map<UpdateMethod, List<URI>> sourceMap,
|
||||
String newVersion, String minVersion) {
|
||||
if (type == NEWS) {
|
||||
if (type == NEWS || type == NEWS_SU3) {
|
||||
// shortcut
|
||||
notifyInstalled(NEWS, "", newVersion);
|
||||
notifyInstalled(type, "", newVersion);
|
||||
return true;
|
||||
}
|
||||
UpdateItem ui = new UpdateItem(type, id);
|
||||
@@ -806,6 +808,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
||||
String msg = null;
|
||||
switch (type) {
|
||||
case NEWS:
|
||||
case NEWS_SU3:
|
||||
break;
|
||||
|
||||
case ROUTER_UNSIGNED:
|
||||
@@ -900,6 +903,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
||||
String msg = null;
|
||||
switch (task.getType()) {
|
||||
case NEWS:
|
||||
case NEWS_SU3:
|
||||
case ROUTER_SIGNED:
|
||||
case ROUTER_SIGNED_SU3:
|
||||
case ROUTER_UNSIGNED:
|
||||
@@ -1009,6 +1013,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
||||
switch (task.getType()) {
|
||||
case TYPE_DUMMY:
|
||||
case NEWS:
|
||||
case NEWS_SU3:
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
@@ -1132,6 +1137,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
||||
|
||||
switch (type) {
|
||||
case NEWS:
|
||||
case NEWS_SU3:
|
||||
// handled in NewsHandler
|
||||
break;
|
||||
|
||||
|
@@ -124,6 +124,7 @@ class NewsFetcher extends UpdateRunner {
|
||||
* Parse the installed (not the temp) news file for the latest version.
|
||||
* TODO: Real XML parsing
|
||||
* TODO: Check minVersion, use backup URLs specified
|
||||
* TODO: SU3
|
||||
*/
|
||||
void checkForUpdates() {
|
||||
FileInputStream in = null;
|
||||
|
@@ -29,6 +29,7 @@ class NewsHandler extends UpdateHandler implements Checker {
|
||||
* @since 0.7.14 not configurable
|
||||
*/
|
||||
private static final String BACKUP_NEWS_URL = "http://avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a.b32.i2p/news.xml";
|
||||
private static final String BACKUP_NEWS_URL_SU3 = "http://avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a.b32.i2p/news.su3";
|
||||
|
||||
public NewsHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
|
||||
super(ctx, mgr);
|
||||
@@ -41,14 +42,17 @@ class NewsHandler extends UpdateHandler implements Checker {
|
||||
*/
|
||||
public UpdateTask check(UpdateType type, UpdateMethod method,
|
||||
String id, String currentVersion, long maxTime) {
|
||||
if ((type != ROUTER_SIGNED && type != NEWS) ||
|
||||
if ((type != ROUTER_SIGNED && type != NEWS && type != NEWS_SU3) ||
|
||||
method != HTTP)
|
||||
return null;
|
||||
List<URI> updateSources = new ArrayList<URI>(2);
|
||||
try {
|
||||
// TODO SU3
|
||||
updateSources.add(new URI(ConfigUpdateHelper.getNewsURL(_context)));
|
||||
} catch (URISyntaxException use) {}
|
||||
try {
|
||||
// TODO
|
||||
//updateSources.add(new URI(BACKUP_NEWS_URL_SU3));
|
||||
updateSources.add(new URI(BACKUP_NEWS_URL));
|
||||
} catch (URISyntaxException use) {}
|
||||
UpdateRunner update = new NewsFetcher(_context, _mgr, updateSources);
|
||||
|
@@ -59,7 +59,7 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
}
|
||||
if (_action.equals(_("Install Plugin"))) {
|
||||
if (pluginsEnabled &&
|
||||
(_context.getBooleanProperty(ConfigClientsHelper.PROP_ENABLE_PLUGIN_INSTALL) ||
|
||||
(_context.getBooleanPropertyDefaultTrue(ConfigClientsHelper.PROP_ENABLE_PLUGIN_INSTALL) ||
|
||||
isAdvanced()))
|
||||
installPlugin();
|
||||
else
|
||||
|
@@ -39,7 +39,12 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
/** @since 0.9.14.1 */
|
||||
public boolean isPluginInstallEnabled() {
|
||||
return PluginStarter.pluginsEnabled(_context) &&
|
||||
(_context.getBooleanProperty(PROP_ENABLE_PLUGIN_INSTALL) || isAdvanced());
|
||||
(_context.getBooleanPropertyDefaultTrue(PROP_ENABLE_PLUGIN_INSTALL) || isAdvanced());
|
||||
}
|
||||
|
||||
/** @since 0.9.15 */
|
||||
public boolean isPluginUpdateEnabled() {
|
||||
return !PluginStarter.getPlugins().isEmpty();
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
|
@@ -32,6 +32,7 @@ public class ConfigUpdateHandler extends FormHandler {
|
||||
// public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
|
||||
public static final String OLD_DEFAULT_NEWS_URL = "http://complication.i2p/news.xml";
|
||||
public static final String DEFAULT_NEWS_URL = "http://echelon.i2p/i2p/news.xml";
|
||||
public static final String DEFAULT_NEWS_URL_SU3 = "http://echelon.i2p/i2p/news.su3";
|
||||
public static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency";
|
||||
public static final long DEFAULT_REFRESH_FREQ = 36*60*60*1000l;
|
||||
public static final String DEFAULT_REFRESH_FREQUENCY = Long.toString(DEFAULT_REFRESH_FREQ);
|
||||
|
@@ -32,6 +32,7 @@ public class ConfigUpdateHelper extends HelperBase {
|
||||
/** hack to replace the old news location with the new one, even if they have saved
|
||||
the update page at some point */
|
||||
public static String getNewsURL(I2PAppContext ctx) {
|
||||
// TODO SU3
|
||||
String url = ctx.getProperty(ConfigUpdateHandler.PROP_NEWS_URL);
|
||||
if (url != null && !url.equals(ConfigUpdateHandler.OLD_DEFAULT_NEWS_URL))
|
||||
return url;
|
||||
|
@@ -9,6 +9,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
@@ -29,6 +30,17 @@ public class LogsHelper extends HelperBase {
|
||||
return Server.getVersion();
|
||||
}
|
||||
|
||||
/** @since 0.9.15 */
|
||||
public String getUnavailableCrypto() {
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
for (SigType t : SigType.values()) {
|
||||
if (!t.isAvailable()) {
|
||||
buf.append("<b>Crypto:</b> ").append(t.toString()).append(" unavailable<br>");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not call logManager.flush(); call getCriticalLogs() first to flush
|
||||
*/
|
||||
|
@@ -105,7 +105,10 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
<input type="submit" name="action" class="accept" value="<%=intl._("Save WebApp Configuration")%>" />
|
||||
</div></form></div>
|
||||
|
||||
<% if (clientshelper.showPlugins()) { %>
|
||||
<%
|
||||
if (clientshelper.showPlugins()) {
|
||||
if (clientshelper.isPluginUpdateEnabled()) {
|
||||
%>
|
||||
<h3><a name="pconfig"></a><%=intl._("Plugin Configuration")%></h3><p>
|
||||
<%=intl._("The plugins listed below are started by the webConsole client.")%>
|
||||
</p><div class="wideload">
|
||||
@@ -116,25 +119,47 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
|
||||
<input type="submit" name="action" class="accept" value="<%=intl._("Save Plugin Configuration")%>" />
|
||||
</div></form></div>
|
||||
|
||||
<% if (clientshelper.isPluginInstallEnabled()) { %>
|
||||
<%
|
||||
} // pluginUpdateEnabled
|
||||
if (clientshelper.isPluginInstallEnabled()) {
|
||||
%>
|
||||
<h3><a name="plugin"></a><%=intl._("Plugin Installation")%></h3><p>
|
||||
<%=intl._("Look for available plugins on {0}.", "<a href=\"http://plugins.i2p\">plugins.i2p</a>")%>
|
||||
<%=intl._("To install a plugin, enter the download URL:")%>
|
||||
</p><div class="wideload">
|
||||
</p>
|
||||
<%
|
||||
} // pluginInstallEnabled
|
||||
if (clientshelper.isPluginInstallEnabled() || clientshelper.isPluginUpdateEnabled()) {
|
||||
%>
|
||||
<div class="wideload">
|
||||
<form action="configclients" method="POST">
|
||||
<input type="hidden" name="nonce" value="<%=pageNonce%>" >
|
||||
<%
|
||||
if (clientshelper.isPluginInstallEnabled()) {
|
||||
%>
|
||||
<p>
|
||||
<input type="text" size="60" name="pluginURL" >
|
||||
</p><hr><div class="formaction">
|
||||
<input type="submit" name="action" class="default" value="<%=intl._("Install Plugin")%>" />
|
||||
<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
|
||||
<input type="submit" name="action" class="download" value="<%=intl._("Install Plugin")%>" />
|
||||
</div><hr><div class="formaction">
|
||||
<input type="submit" name="action" class="reload" value="<%=intl._("Update All Installed Plugins")%>" />
|
||||
</div></form></div>
|
||||
</div>
|
||||
<%
|
||||
} // pluginInstallEnabled
|
||||
} // showPlugins
|
||||
} // pluginInstallEnabled
|
||||
%>
|
||||
</div>
|
||||
<%
|
||||
if (clientshelper.isPluginUpdateEnabled()) {
|
||||
%>
|
||||
<hr><div class="formaction">
|
||||
<input type="submit" name="action" class="reload" value="<%=intl._("Update All Installed Plugins")%>" />
|
||||
</div>
|
||||
<%
|
||||
} // pluginUpdateEnabled
|
||||
%>
|
||||
</form></div>
|
||||
<%
|
||||
} // pluginInstallEnabled || pluginUpdateEnabled
|
||||
} // showPlugins
|
||||
%>
|
||||
</div></div></body></html>
|
||||
|
@@ -60,9 +60,10 @@
|
||||
<p>
|
||||
<b>I2P version:</b> <%=net.i2p.router.RouterVersion.FULL_VERSION%><br>
|
||||
<b>Java version:</b> <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)<br>
|
||||
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
|
||||
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />
|
||||
<jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute(\"i2p.contextId\")%>" />
|
||||
<jsp:getProperty name="logsHelper" property="unavailableCrypto" />
|
||||
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
|
||||
<b>Server version:</b> <jsp:getProperty name="logsHelper" property="jettyVersion" /><br>
|
||||
<b>Servlet version:</b> <%=getServletInfo()%><br>
|
||||
<b>Platform:</b> <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%><br>
|
||||
|
@@ -24,16 +24,18 @@
|
||||
<p>
|
||||
<b>I2P version:</b> <%=net.i2p.router.RouterVersion.FULL_VERSION%><br>
|
||||
<b>Java version:</b> <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)<br>
|
||||
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
|
||||
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />
|
||||
<jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute(\"i2p.contextId\")%>" />
|
||||
<jsp:getProperty name="logsHelper" property="unavailableCrypto" />
|
||||
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
|
||||
<b>Server version:</b> <jsp:getProperty name="logsHelper" property="jettyVersion" /><br>
|
||||
<b>Servlet version:</b> <%=getServletInfo()%><br>
|
||||
<b>Platform:</b> <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%><br>
|
||||
<b>Processor:</b> <%=net.i2p.util.NativeBigInteger.cpuModel()%> (<%=net.i2p.util.NativeBigInteger.cpuType()%>)<br>
|
||||
<b>Jbigi:</b> <%=net.i2p.util.NativeBigInteger.loadStatus()%><br>
|
||||
<b>Encoding:</b> <%=System.getProperty("file.encoding")%><br>
|
||||
<b>Charset:</b> <%=java.nio.charset.Charset.defaultCharset().name()%></p>
|
||||
<b>Charset:</b> <%=java.nio.charset.Charset.defaultCharset().name()%><br>
|
||||
</p>
|
||||
<p><%=intl._("Note that system information, log timestamps, and log messages may provide clues to your location; please review everything you include in a bug report.")%></p>
|
||||
<h3><%=intl._("Critical Logs")%></h3><a name="criticallogs"> </a>
|
||||
<jsp:getProperty name="logsHelper" property="criticalLogs" />
|
||||
|
@@ -13,6 +13,7 @@ import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SigningPublicKey;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -314,10 +315,16 @@ class Packet {
|
||||
|
||||
private void setFlags(int flags) { _flags = flags; }
|
||||
|
||||
/** the signature on the packet (only included if the flag for it is set)
|
||||
/**
|
||||
* The signature on the packet (only included if the flag for it is set)
|
||||
*
|
||||
* Warning, may be typed wrong on incoming packets for EdDSA
|
||||
* before verifySignature() is called.
|
||||
*
|
||||
* @return signature on the packet if the flag for signatures is set
|
||||
*/
|
||||
public Signature getOptionalSignature() { return _optionSignature; }
|
||||
|
||||
public void setOptionalSignature(Signature sig) {
|
||||
setFlag(FLAG_SIGNATURE_INCLUDED, sig != null);
|
||||
_optionSignature = sig;
|
||||
@@ -327,6 +334,7 @@ class Packet {
|
||||
* @return the sending Destination
|
||||
*/
|
||||
public Destination getOptionalFrom() { return _optionFrom; }
|
||||
|
||||
public void setOptionalFrom(Destination from) {
|
||||
setFlag(FLAG_FROM_INCLUDED, from != null);
|
||||
if (from == null) throw new RuntimeException("from is null!?");
|
||||
@@ -340,6 +348,7 @@ class Packet {
|
||||
* @return How long the sender wants the recipient to wait before sending any more data in ms.
|
||||
*/
|
||||
public int getOptionalDelay() { return _optionDelay; }
|
||||
|
||||
public void setOptionalDelay(int delayMs) {
|
||||
if (delayMs > MAX_DELAY_REQUEST)
|
||||
_optionDelay = MAX_DELAY_REQUEST;
|
||||
@@ -507,20 +516,21 @@ class Packet {
|
||||
* @throws IllegalStateException
|
||||
*/
|
||||
private int writtenSize() {
|
||||
int size = 0;
|
||||
size += 4; // _sendStreamId.length;
|
||||
size += 4; // _receiveStreamId.length;
|
||||
size += 4; // sequenceNum
|
||||
size += 4; // ackThrough
|
||||
//int size = 0;
|
||||
//size += 4; // _sendStreamId.length;
|
||||
//size += 4; // _receiveStreamId.length;
|
||||
//size += 4; // sequenceNum
|
||||
//size += 4; // ackThrough
|
||||
// size++; // nacks length
|
||||
//size++; // resendDelay
|
||||
//size += 2; // flags
|
||||
//size += 2; // option size
|
||||
int size = 22;
|
||||
|
||||
if (_nacks != null) {
|
||||
size++; // nacks length
|
||||
// if max win is ever > 255, limit to 255
|
||||
size += 4 * _nacks.length;
|
||||
} else {
|
||||
size++; // nacks length
|
||||
}
|
||||
size++; // resendDelay
|
||||
size += 2; // flags
|
||||
|
||||
if (isFlagSet(FLAG_DELAY_REQUESTED))
|
||||
size += 2;
|
||||
@@ -531,8 +541,6 @@ class Packet {
|
||||
if (isFlagSet(FLAG_SIGNATURE_INCLUDED))
|
||||
size += _optionSignature.length();
|
||||
|
||||
size += 2; // option size
|
||||
|
||||
if (_payload != null) {
|
||||
size += _payload.getValid();
|
||||
}
|
||||
@@ -632,6 +640,9 @@ class Packet {
|
||||
// super cheat for now, look for correct type,
|
||||
// assume no more options. If we add to the options
|
||||
// we will have to ask the manager.
|
||||
// We will get this wrong for Ed25519, same length as P256...
|
||||
// See verifySignature() below where we will recast the signature to
|
||||
// the correct type if necessary
|
||||
int siglen = payloadBegin - cur;
|
||||
SigType type = null;
|
||||
for (SigType t : SigType.values()) {
|
||||
@@ -677,12 +688,27 @@ class Packet {
|
||||
|
||||
if (buffer == null)
|
||||
buffer = new byte[size];
|
||||
int written = writePacket(buffer, 0, from.getSigningPublicKey().getType().getSigLen());
|
||||
SigningPublicKey spk = from.getSigningPublicKey();
|
||||
SigType type = spk.getType();
|
||||
if (type == null) {
|
||||
Log l = ctx.logManager().getLog(Packet.class);
|
||||
if (l.shouldLog(Log.WARN))
|
||||
l.warn("Unknown sig type in " + from + " cannot verify " + toString());
|
||||
return false;
|
||||
}
|
||||
int written = writePacket(buffer, 0, type.getSigLen());
|
||||
if (written != size) {
|
||||
ctx.logManager().getLog(Packet.class).error("Written " + written + " size " + size + " for " + toString(), new Exception("moo"));
|
||||
return false;
|
||||
}
|
||||
boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, from.getSigningPublicKey());
|
||||
|
||||
// Fixup of signature if we guessed wrong on the type in readPacket(), which could happen
|
||||
// on a close or reset packet where we have a signature without a FROM
|
||||
if (type != _optionSignature.getType() &&
|
||||
type.getSigLen() == _optionSignature.length())
|
||||
_optionSignature = new Signature(type, _optionSignature.getData());
|
||||
|
||||
boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, spk);
|
||||
if (!ok) {
|
||||
Log l = ctx.logManager().getLog(Packet.class);
|
||||
if (l.shouldLog(Log.WARN))
|
||||
|
@@ -91,3 +91,9 @@ javac.version=1.6
|
||||
# Optional properties used in tests to enable additional tools.
|
||||
#with.cobertura=/PATH/TO/cobertura.jar
|
||||
#with.clover=/PATH/TO/clover.jar
|
||||
|
||||
### Bundle router infos ###
|
||||
# Set to bundle router infos from your local I2P install in the package
|
||||
#bundle.routerInfos=true
|
||||
#bundle.routerInfos.count=200
|
||||
#bundle.routerInfos.i2pConfigDir=/PATH/TO/.i2p
|
||||
|
30
build.xml
30
build.xml
@@ -960,7 +960,7 @@
|
||||
<copy file="installer/lib/wrapper/all/wrapper.jar" todir="pkg-temp/lib" />
|
||||
</target>
|
||||
|
||||
<target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates">
|
||||
<target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates, prepRouterInfos">
|
||||
<!-- if updater200 was run previously, it left *.pack files in pkg-temp -->
|
||||
<!-- Also remove deletelist.txt used for updater only -->
|
||||
<delete>
|
||||
@@ -1017,6 +1017,9 @@
|
||||
<fileset dir="installer/resources/icons/flags/" includes="cn.png de.png es.png fr.png ir.png it.png jp.png nl.png ru.png se.png us.png" />
|
||||
</copy>
|
||||
<copy file="installer/resources/themes/console/images/favicon.ico" tofile="pkg-temp/eepsite/docroot/favicon.ico" />
|
||||
<copy todir="pkg-temp/docs/icons/flags" >
|
||||
<fileset dir="installer/resources/icons/flags" />
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="preplicenses">
|
||||
@@ -1051,6 +1054,26 @@
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<condition property="no.bundle.routerInfos">
|
||||
<isfalse value="${bundle.routerInfos}" />
|
||||
</condition>
|
||||
|
||||
<target name="prepRouterInfos" depends="buildrouter" unless="no.bundle.routerInfos">
|
||||
<mkdir dir="pkg-temp/netDb" />
|
||||
<java classname="net.i2p.router.networkdb.kademlia.PersistentDataStore" fork="true" failonerror="true">
|
||||
<classpath>
|
||||
<pathelement location="build/i2p.jar" />
|
||||
<pathelement location="build/router.jar" />
|
||||
</classpath>
|
||||
<arg value="-i" />
|
||||
<arg value="${bundle.routerInfos.i2pConfigDir}" />
|
||||
<arg value="-o" />
|
||||
<arg value="pkg-temp/netDb" />
|
||||
<arg value="-c" />
|
||||
<arg value="${bundle.routerInfos.count}" />
|
||||
</java>
|
||||
</target>
|
||||
|
||||
<!-- this is no longer required, izpack 4.3.0 supports headless installs with java -jar i2pinstall.exe -console -->
|
||||
<!-- and this is no longer used by the SlackBuild -->
|
||||
<target name="tarball" depends="preppkg">
|
||||
@@ -1237,11 +1260,6 @@
|
||||
<copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
|
||||
<copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
|
||||
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
|
||||
<!--
|
||||
<copy todir="pkg-temp/docs/icons/flags" >
|
||||
<fileset dir="installer/resources/icons/flags" />
|
||||
</copy>
|
||||
-->
|
||||
</target>
|
||||
|
||||
<!-- All jetty jars required for update.
|
||||
|
@@ -42,6 +42,7 @@ import java.security.interfaces.ECKey;
|
||||
import java.security.interfaces.RSAKey;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine;
|
||||
import net.i2p.crypto.eddsa.EdDSAKey;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.Signature;
|
||||
@@ -517,7 +518,7 @@ public class DSAEngine {
|
||||
|
||||
java.security.Signature jsig;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
|
||||
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(type.getDigestInstance());
|
||||
jsig = new EdDSAEngine(type.getDigestInstance());
|
||||
else
|
||||
jsig = java.security.Signature.getInstance(type.getAlgorithmName());
|
||||
PublicKey pubKey = SigUtil.toJavaKey(verifyingKey);
|
||||
@@ -566,7 +567,7 @@ public class DSAEngine {
|
||||
String algo = getRawAlgo(type);
|
||||
java.security.Signature jsig;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
|
||||
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
|
||||
jsig = new EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
|
||||
else
|
||||
jsig = java.security.Signature.getInstance(algo);
|
||||
jsig.initVerify(pubKey);
|
||||
@@ -608,7 +609,7 @@ public class DSAEngine {
|
||||
|
||||
java.security.Signature jsig;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
|
||||
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(type.getDigestInstance());
|
||||
jsig = new EdDSAEngine(type.getDigestInstance());
|
||||
else
|
||||
jsig = java.security.Signature.getInstance(type.getAlgorithmName());
|
||||
PrivateKey privKey = SigUtil.toJavaKey(privateKey);
|
||||
@@ -651,7 +652,7 @@ public class DSAEngine {
|
||||
|
||||
java.security.Signature jsig;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
|
||||
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
|
||||
jsig = new EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
|
||||
else
|
||||
jsig = java.security.Signature.getInstance(algo);
|
||||
jsig.initSign(privKey, _context.random());
|
||||
|
@@ -123,6 +123,7 @@ class ECConstants {
|
||||
Gy= 07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811
|
||||
*/
|
||||
|
||||
/*
|
||||
private static final ECParms PARM_P192 = new ECParms(
|
||||
// P N Seed B Gx Gy
|
||||
"6277101735386680763835789423207666416083908700390324961279",
|
||||
@@ -132,6 +133,7 @@ class ECConstants {
|
||||
"188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012",
|
||||
"07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"
|
||||
);
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
@@ -318,17 +320,17 @@ class ECConstants {
|
||||
// standard curve names
|
||||
// first is OpenJDK 6/7
|
||||
// second is BC
|
||||
public static final ECParameterSpec P192_SPEC = genSpec("secp192r1", "P-192", PARM_P192);
|
||||
//public static final ECParameterSpec P192_SPEC = genSpec("secp192r1", "P-192", PARM_P192);
|
||||
public static final ECParameterSpec P256_SPEC = genSpec("secp256r1", "P-256", PARM_P256);
|
||||
public static final ECParameterSpec P384_SPEC = genSpec("secp384r1", "P-384", PARM_P384);
|
||||
public static final ECParameterSpec P521_SPEC = genSpec("secp521r1", "P-521", PARM_P521);
|
||||
|
||||
// Koblitz
|
||||
public static final ECParameterSpec K163_SPEC = genSpec("sect163k1", "K-163", null);
|
||||
public static final ECParameterSpec K233_SPEC = genSpec("sect233k1", "K-233", null);
|
||||
public static final ECParameterSpec K283_SPEC = genSpec("sect283k1", "K-283", null);
|
||||
public static final ECParameterSpec K409_SPEC = genSpec("sect409k1", "K-409", null);
|
||||
public static final ECParameterSpec K571_SPEC = genSpec("sect571k1", "K-571", null);
|
||||
//public static final ECParameterSpec K163_SPEC = genSpec("sect163k1", "K-163", null);
|
||||
//public static final ECParameterSpec K233_SPEC = genSpec("sect233k1", "K-233", null);
|
||||
//public static final ECParameterSpec K283_SPEC = genSpec("sect283k1", "K-283", null);
|
||||
//public static final ECParameterSpec K409_SPEC = genSpec("sect409k1", "K-409", null);
|
||||
//public static final ECParameterSpec K571_SPEC = genSpec("sect571k1", "K-571", null);
|
||||
|
||||
|
||||
}
|
||||
|
@@ -67,12 +67,16 @@ public class SU3File {
|
||||
private static final int VERSION_OFFSET = 40; // Signature.SIGNATURE_BYTES; avoid early ctx init
|
||||
|
||||
public static final int TYPE_ZIP = 0;
|
||||
/** @since 0.9.15 */
|
||||
public static final int TYPE_XML = 1;
|
||||
/** @since 0.9.15 */
|
||||
public static final int TYPE_HTML = 2;
|
||||
|
||||
public static final int CONTENT_UNKNOWN = 0;
|
||||
public static final int CONTENT_ROUTER = 1;
|
||||
public static final int CONTENT_PLUGIN = 2;
|
||||
public static final int CONTENT_RESEED = 3;
|
||||
/** @since 0.9.15 */
|
||||
public static final int CONTENT_NEWS = 4;
|
||||
|
||||
private enum ContentType {
|
||||
|
@@ -95,6 +95,7 @@ public enum SigType {
|
||||
private final SigAlgo base;
|
||||
private final String digestName, algoName, since;
|
||||
private final AlgorithmParameterSpec params;
|
||||
private final boolean isAvail;
|
||||
|
||||
SigType(int cod, int pubLen, int privLen, int hLen, int sLen, SigAlgo baseAlgo,
|
||||
String mdName, String aName, AlgorithmParameterSpec pSpec, String supportedSince) {
|
||||
@@ -108,6 +109,7 @@ public enum SigType {
|
||||
algoName = aName;
|
||||
params = pSpec;
|
||||
since = supportedSince;
|
||||
isAvail = x_isAvailable();
|
||||
}
|
||||
|
||||
/** the unique identifier for this type */
|
||||
@@ -180,6 +182,10 @@ public enum SigType {
|
||||
* @return true if supported in this JVM
|
||||
*/
|
||||
public boolean isAvailable() {
|
||||
return isAvail;
|
||||
}
|
||||
|
||||
private boolean x_isAvailable() {
|
||||
if (DSA_SHA1 == this)
|
||||
return true;
|
||||
try {
|
||||
|
@@ -16,6 +16,7 @@ import net.i2p.crypto.eddsa.math.GroupElement;
|
||||
import net.i2p.crypto.eddsa.math.ScalarOps;
|
||||
|
||||
/**
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -4,6 +4,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
|
||||
|
||||
/**
|
||||
* Common interface for all EdDSA keys.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -8,6 +8,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||
|
||||
/**
|
||||
* An EdDSA private key.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -8,6 +8,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
|
||||
/**
|
||||
* An EdDSA public key.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -12,6 +12,7 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
|
||||
/**
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -17,6 +17,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
|
||||
/**
|
||||
* Default strength is 256
|
||||
*
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public class KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
private static final int DEFAULT_STRENGTH = 256;
|
||||
|
@@ -1,6 +1,10 @@
|
||||
package net.i2p.crypto.eddsa;
|
||||
|
||||
/**
|
||||
* Basic utilities for eddsa.
|
||||
* Not for external use, not maintained as a public API.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
@@ -18,6 +22,18 @@ public class Utils {
|
||||
return (result ^ 0x01) & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant-time byte[] comparison.
|
||||
* @return 1 if b and c are equal, 0 otherwise.
|
||||
*/
|
||||
public static int equal(byte[] b, byte[] c) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
result |= b[i] ^ c[i];
|
||||
}
|
||||
return ~equal(result, 0) & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant-time determine if byte is negative.
|
||||
* @param b the byte to check.
|
||||
@@ -34,7 +50,7 @@ public class Utils {
|
||||
* @return 0 or 1, the value of the i'th bit in h
|
||||
*/
|
||||
public static int bit(byte[] h, int i) {
|
||||
return (h[i/8] >> (i%8)) & 1;
|
||||
return (h[i >> 3] >> (i & 7)) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,4 +67,22 @@ public class Utils {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts bytes to a hex string.
|
||||
* @param raw the byte[] to be converted.
|
||||
* @return the hex representation as a string.
|
||||
*/
|
||||
public static String bytesToHex(byte[] raw) {
|
||||
if ( raw == null ) {
|
||||
return null;
|
||||
}
|
||||
final StringBuilder hex = new StringBuilder(2 * raw.length);
|
||||
for (final byte b : raw) {
|
||||
hex.append(Character.forDigit((b & 0xF0) >> 4, 16))
|
||||
.append(Character.forDigit((b & 0x0F), 16));
|
||||
}
|
||||
return hex.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,6 +5,8 @@ import java.io.Serializable;
|
||||
/**
|
||||
* A twisted Edwards curve.
|
||||
* Points on the curve satisfy -x^2 + y^2 = 1 + d x^2y^2
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -3,6 +3,8 @@ package net.i2p.crypto.eddsa.math;
|
||||
/**
|
||||
* Common interface for all (b-1)-bit encodings of elements
|
||||
* of EdDSA finite fields.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
@@ -22,7 +24,7 @@ public abstract class Encoding {
|
||||
/**
|
||||
* Decode a FieldElement from its (b-1)-bit encoding.
|
||||
* The highest bit is masked out.
|
||||
* @param val the (b-1)-bit encoding of a FieldElement.
|
||||
* @param in the (b-1)-bit encoding of a FieldElement.
|
||||
* @return the FieldElement represented by 'val'.
|
||||
*/
|
||||
public abstract FieldElement decode(byte[] in);
|
||||
@@ -33,7 +35,7 @@ public abstract class Encoding {
|
||||
* than the (b-1)-bit encoding of -x. If q is an odd prime and the encoding
|
||||
* is the little-endian representation of {0, 1,..., q-1} then the negative
|
||||
* elements of F_q are {1, 3, 5,..., q-2}.
|
||||
* @return
|
||||
* @return true if negative
|
||||
*/
|
||||
public abstract boolean isNegative(FieldElement x);
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@ import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* An EdDSA finite field. Includes several pre-computed values.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -1,5 +1,10 @@
|
||||
package net.i2p.crypto.eddsa.math;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.15
|
||||
*
|
||||
*/
|
||||
public abstract class FieldElement {
|
||||
protected final Field f;
|
||||
|
||||
|
@@ -6,6 +6,8 @@ import net.i2p.crypto.eddsa.Utils;
|
||||
|
||||
/**
|
||||
* A point (x,y) on an EdDSA curve.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
@@ -489,7 +491,7 @@ public class GroupElement implements Serializable {
|
||||
*
|
||||
* @param pos = i/2 for i in {0, 2, 4,..., 62}
|
||||
* @param b = r_i
|
||||
* @return
|
||||
* @return the GroupElement
|
||||
*/
|
||||
GroupElement select(int pos, int b) {
|
||||
// Is r_i negative?
|
||||
@@ -522,7 +524,7 @@ public class GroupElement implements Serializable {
|
||||
* Preconditions: (TODO: Check this applies here)
|
||||
* a[31] <= 127
|
||||
* @param a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
* @return
|
||||
* @return the GroupElement
|
||||
*/
|
||||
public GroupElement scalarMultiply(byte[] a) {
|
||||
GroupElement t;
|
||||
@@ -603,7 +605,7 @@ public class GroupElement implements Serializable {
|
||||
* @param A in P3 representation.
|
||||
* @param a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
* @param b = b[0]+256*b[1]+...+256^31 b[31]
|
||||
* @return
|
||||
* @return the GroupElement
|
||||
*/
|
||||
public GroupElement doubleScalarMultiplyVariableTime(GroupElement A, byte[] a, byte[] b) {
|
||||
byte[] aslide = slide(a);
|
||||
@@ -645,7 +647,6 @@ public class GroupElement implements Serializable {
|
||||
|
||||
/**
|
||||
* Verify that a point is on its curve.
|
||||
* @param P The point to check.
|
||||
* @return true if the point lies on its curve.
|
||||
*/
|
||||
public boolean isOnCurve() {
|
||||
|
@@ -1,5 +1,10 @@
|
||||
package net.i2p.crypto.eddsa.math;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.15
|
||||
*
|
||||
*/
|
||||
public interface ScalarOps {
|
||||
/**
|
||||
* Reduce the given scalar mod l.
|
||||
|
@@ -65,7 +65,7 @@ public class BigIntegerLittleEndianEncoding extends Encoding implements Serializ
|
||||
* than the (b-1)-bit encoding of -x. If q is an odd prime and the encoding
|
||||
* is the little-endian representation of {0, 1,..., q-1} then the negative
|
||||
* elements of F_q are {1, 3, 5,..., q-2}.
|
||||
* @return
|
||||
* @return true if negative
|
||||
*/
|
||||
public boolean isNegative(FieldElement x) {
|
||||
return ((BigIntegerFieldElement)x).bi.testBit(0);
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<html><body>
|
||||
<p>
|
||||
Low-level, non-optimized implementation using BigIntegers for any curve.
|
||||
Unused. See the <a href="../ed25519/package-summary.html">ed25519</a> implementation for Curve 25519.
|
||||
</p>
|
||||
</body></html>
|
@@ -1,8 +1,8 @@
|
||||
package net.i2p.crypto.eddsa.math.ed25519;
|
||||
|
||||
import net.i2p.crypto.eddsa.Utils;
|
||||
import net.i2p.crypto.eddsa.math.Field;
|
||||
import net.i2p.crypto.eddsa.math.FieldElement;
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* An element t, entries t[0]...t[9], represents the integer
|
||||
@@ -26,11 +26,7 @@ public class Ed25519FieldElement extends FieldElement {
|
||||
|
||||
public boolean isNonZero() {
|
||||
byte[] s = toByteArray();
|
||||
int result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
result |= s[i] ^ zero[i];
|
||||
}
|
||||
return result != 0;
|
||||
return Utils.equal(s, zero) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -959,13 +955,11 @@ public class Ed25519FieldElement extends FieldElement {
|
||||
if (!(obj instanceof Ed25519FieldElement))
|
||||
return false;
|
||||
Ed25519FieldElement fe = (Ed25519FieldElement) obj;
|
||||
// XXX why does direct byte[] comparison fail?
|
||||
// TODO should this be constant time?
|
||||
return DataHelper.toString(toByteArray()).equals(DataHelper.toString(fe.toByteArray()));
|
||||
return 1==Utils.equal(toByteArray(), fe.toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Ed25519FieldElement val="+DataHelper.toString(toByteArray())+"]";
|
||||
return "[Ed25519FieldElement val="+Utils.bytesToHex(toByteArray())+"]";
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<html><body>
|
||||
<p>
|
||||
Low-level, optimized implementation using Radix 2^51 for Curve 25519.
|
||||
See the <a href="../bigint/package-summary.html">bigint</a> implementation for other curves.
|
||||
</p>
|
||||
</body></html>
|
9
core/java/src/net/i2p/crypto/eddsa/math/package.html
Normal file
9
core/java/src/net/i2p/crypto/eddsa/math/package.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html><body>
|
||||
<p>
|
||||
Data structures that definie curves and fields, and
|
||||
the mathematical operaions on them.
|
||||
</p><p>
|
||||
Low-level implementation is in <a href="bigint/package-summary.html">bigint</a> for any curve using BigIntegers,
|
||||
and in <a href="ed25519/package-summary.html">ed25519</a> for Curve 25519 using Radix 2^51.
|
||||
</p>
|
||||
</body></html>
|
11
core/java/src/net/i2p/crypto/eddsa/package.html
Normal file
11
core/java/src/net/i2p/crypto/eddsa/package.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html><body>
|
||||
<p>
|
||||
Java implementation of EdDSA, a digital signature scheme using
|
||||
a variant of elliptic curve cryptography based on Twisted Edwards curves.
|
||||
</p><p>
|
||||
Contains a generic implementation for any curve using BigIntegers,
|
||||
and an optimized implementation for Curve 25519 using Radix 2^51.
|
||||
</p><p>
|
||||
Since 0.9.15.
|
||||
</p>
|
||||
</body></html>
|
@@ -5,6 +5,8 @@ import java.security.spec.AlgorithmParameterSpec;
|
||||
/**
|
||||
* Implementation of AlgorithmParameterSpec that holds the name of a named
|
||||
* EdDSA curve specification.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -6,6 +6,8 @@ import net.i2p.crypto.eddsa.math.ScalarOps;
|
||||
|
||||
/**
|
||||
* EdDSA Curve specification that can also be referred to by name.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -10,6 +10,8 @@ import net.i2p.crypto.eddsa.math.ed25519.Ed25519ScalarOps;
|
||||
|
||||
/**
|
||||
* The named EdDSA curves.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -12,6 +12,8 @@ import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Parameter specification for an EdDSA algorithm.
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -8,6 +8,8 @@ import java.util.Arrays;
|
||||
import net.i2p.crypto.eddsa.math.GroupElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
@@ -5,6 +5,8 @@ import java.security.spec.KeySpec;
|
||||
import net.i2p.crypto.eddsa.math.GroupElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.15
|
||||
* @author str4d
|
||||
*
|
||||
*/
|
||||
|
6
core/java/src/net/i2p/crypto/eddsa/spec/package.html
Normal file
6
core/java/src/net/i2p/crypto/eddsa/spec/package.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html><body>
|
||||
<p>
|
||||
Specifications for curves and keys, and a table for named curves,
|
||||
initially containing only the 25519 curve "ed25519-sha-512".
|
||||
</p>
|
||||
</body></html>
|
11
core/java/src/net/i2p/crypto/provider/package.html
Normal file
11
core/java/src/net/i2p/crypto/provider/package.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html><body>
|
||||
<p>
|
||||
I2P implementation of java.security.Provider for EdDSA.
|
||||
</p><p>
|
||||
This should only be required when
|
||||
using runtime registration of the provider with the
|
||||
<code>Security.addProvider()</code> mechanism.
|
||||
</p><p>
|
||||
Since 0.9.15. Other I2P algorithms may be added later.
|
||||
</p>
|
||||
</body></html>
|
@@ -104,7 +104,8 @@ public class Destination extends KeysAndCert {
|
||||
}
|
||||
|
||||
/**
|
||||
* deprecated, used only by Packet.java in streaming
|
||||
* Deprecated, used only by Packet.java in streaming.
|
||||
* Broken for sig types P521 and RSA before 0.9.15
|
||||
* @return the written length (NOT the new offset)
|
||||
*/
|
||||
public int writeBytes(byte target[], int offset) {
|
||||
@@ -115,8 +116,9 @@ public class Destination extends KeysAndCert {
|
||||
System.arraycopy(_padding, 0, target, cur, _padding.length);
|
||||
cur += _padding.length;
|
||||
}
|
||||
System.arraycopy(_signingKey.getData(), 0, target, cur, _signingKey.length());
|
||||
cur += _signingKey.length();
|
||||
int spkTrunc = Math.min(SigningPublicKey.KEYSIZE_BYTES, _signingKey.length());
|
||||
System.arraycopy(_signingKey.getData(), 0, target, cur, spkTrunc);
|
||||
cur += spkTrunc;
|
||||
cur += _certificate.writeBytes(target, cur);
|
||||
return cur - offset;
|
||||
}
|
||||
|
@@ -81,7 +81,9 @@ public abstract class SimpleDataStructure extends DataStructureImpl {
|
||||
int length = length();
|
||||
_data = new byte[length];
|
||||
int read = read(in, _data);
|
||||
if (read != length) throw new DataFormatException("Not enough bytes to read the data");
|
||||
if (read != length)
|
||||
throw new DataFormatException("EOF reading " + getClass().getSimpleName() +
|
||||
", read: " + read + ", required: " + length);
|
||||
}
|
||||
|
||||
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||
|
@@ -23,5 +23,7 @@ public enum UpdateType {
|
||||
/** unused */
|
||||
ADDRESSBOOK,
|
||||
/** @since 0.9.9 */
|
||||
ROUTER_SIGNED_SU3
|
||||
ROUTER_SIGNED_SU3,
|
||||
/** @since 0.9.15 */
|
||||
NEWS_SU3
|
||||
}
|
||||
|
@@ -475,7 +475,7 @@ public class NativeBigInteger extends BigInteger {
|
||||
}
|
||||
if (!_nativeOk) {
|
||||
warn("Native BigInteger library jbigi not loaded - using pure Java - " +
|
||||
"poor performance may result - see http://www.i2p2.i2p/jbigi for help");
|
||||
"poor performance may result - see http://i2p-projekt.i2p/jbigi for help");
|
||||
}
|
||||
} catch(Exception e) {
|
||||
warn("Native BigInteger library jbigi not loaded, using pure java", e);
|
||||
|
@@ -26,6 +26,7 @@ public abstract class SystemVersion {
|
||||
|
||||
private static final boolean _oneDotSix;
|
||||
private static final boolean _oneDotSeven;
|
||||
private static final boolean _oneDotEight;
|
||||
private static final int _androidSDK;
|
||||
|
||||
static {
|
||||
@@ -60,9 +61,11 @@ public abstract class SystemVersion {
|
||||
if (_isAndroid) {
|
||||
_oneDotSix = _androidSDK >= 9;
|
||||
_oneDotSeven = _androidSDK >= 19;
|
||||
_oneDotEight = false;
|
||||
} else {
|
||||
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
|
||||
_oneDotSeven = VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
|
||||
_oneDotSeven = _oneDotSix && VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
|
||||
_oneDotEight = _oneDotSeven && VersionComparator.comp(System.getProperty("java.version"), "1.8") >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +130,15 @@ public abstract class SystemVersion {
|
||||
return _oneDotSeven;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if Java 1.8 or higher, false for Android.
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public static boolean isJava8() {
|
||||
return _oneDotEight;
|
||||
}
|
||||
|
||||
/**
|
||||
* This isn't always correct.
|
||||
* http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit
|
||||
|
33
history.txt
33
history.txt
@@ -1,3 +1,36 @@
|
||||
2014-09-09 zzz
|
||||
* i2psnark: Escape fixes
|
||||
|
||||
2014-08-31 zzz
|
||||
* Build: Add support for bundling router infos in the package
|
||||
* I2PTunnel: Allow changing of spoof host and target host/port without
|
||||
restarting server tunnel
|
||||
|
||||
2014-08-30 zzz
|
||||
* Console:
|
||||
- Re-enable plugin installation by default
|
||||
- Don't show configuration section or update-all button if no plugins installed
|
||||
- Show unavailable crypto on /logs
|
||||
* Router: Log warnings for unavailable crypto at startup
|
||||
* RouterInfo: Backport fix for verification of EdDSA RI sig type
|
||||
|
||||
2014-08-28 zzz
|
||||
* Streaming: Fix verify of Ed25519 signatures in CLOSE packets
|
||||
|
||||
2014-08-27 zzz
|
||||
* i2psnark:
|
||||
- Persist uploaded count (tickets #1034, #1298)
|
||||
- Don't retry announce if we get back HTML
|
||||
- Recognize Vuze tracker rejections
|
||||
- Don't retry rejected announces unless seeding
|
||||
- Better UI handling of announces with ports or full destination
|
||||
* NetDB: Don't abort initialization on an unsupported RI sig type
|
||||
* Streaming: Fix P521 and RSA sig types
|
||||
|
||||
2014-08-23 zzz
|
||||
* Console, i2psnark, i2ptunnel: Escape fixes and cleanups
|
||||
* SSU: Drop peer tests as Bob from unestablished Alices
|
||||
|
||||
2014-08-22 zzz
|
||||
* SigTypes:
|
||||
- Add isSupportedSince(), use in floodfill selection
|
||||
|
@@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFhTCCA22gAwIBAgIERiD+VDANBgkqhkiG9w0BAQ0FADBzMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEcMBoGA1UEAwwTenp6LXBsdWdpbkBt
|
||||
YWlsLmkycDAeFw0xNDA4MDcyMTA0NDlaFw0yNDA4MDYyMTA0NDlaMHMxCzAJBgNV
|
||||
BAYTAlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBB
|
||||
bm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRwwGgYDVQQDDBN6enotcGx1
|
||||
Z2luQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzWRY
|
||||
ZFGmPO3lOfD9vu5LFxmZchqEiT+QYyTU1FllIlppgb3dkAo7Tn8R1QcwyKkoJkYI
|
||||
oFdUCYwUOhUmbKv5j6oBTmLlav/MQi2nM7dHfBVP3ubzZP7Z/zKGQUf1Ze7136Yh
|
||||
l6Lfbl/wN3O7IIGs6NksSiq/hnDrAmZAQwfc7/dahPh4gxPRuK9Bg7NFPJyQ07vJ
|
||||
FQC1I2uWb49WL/rzJnR20fSeJa/LJ5JnKnWG6RjbTKHp6wN2S0d389BkJvUCEmeT
|
||||
o5JdV1xcrB4GY/z0gfmS8haZYeW3ySPKuaEOpZGrwLFaKnZGITegMrnVTTZD8RAk
|
||||
SqvJC8+X8pdFN41I9tkwAK/FTtrNxVubPLfvzgQ2Z8WFtLPFWkbEYn58AnKWj59X
|
||||
Zs1delvTF1vJHYSY6ZMmymnOBWmRSofXpByBzBCXVKMWZ8ah7BJKLkzGd2/XYeY/
|
||||
mIRm+SghTjojUg2F3G26W/z67HoSWMunwor0ur2A/r8HMKWqhSzNdEOx9zzX7ihf
|
||||
W3tUbI/E7BDWLs0sd6gmGMSYbxkrB2pM21X9UmpthDazo6CTC+nrNYRjSpDisOiV
|
||||
gnu1fPmbfoa61pRoWAQOHVN+D5mDKeJW+WConOxRKuLY/aymeXwSKBcLLkYHasc/
|
||||
ooJwSofj/SYooGR9aVJO2oEKYbpLu4fFduHIrrMCAwEAAaMhMB8wHQYDVR0OBBYE
|
||||
FADW2hreviSWGPa+xSDnNpUO+ih2MA0GCSqGSIb3DQEBDQUAA4ICAQBePI57drix
|
||||
BLUXhB4rAeyCUaA3hp40gzz5oQKijQF8Z+aP3j74NuCUMuPF0f62mPdq4Yrm/QM4
|
||||
bdKTHtoOuvQyEtnsfRj241CppdzTeVtCMRcBmDUeejE0BjRYtmHOpV7Ylyf3olX+
|
||||
IddPrkKshN+zy0TiNhwWrKG44C2JkmSqFQRicCm34+0dxINBUqv/+srmriBFesdg
|
||||
74Z9EPpXRA1xpB0ud4GTq5NQDPby9mm6tXMrziomLtuG66emW7dtisQcmn59Te6E
|
||||
8OSZrbRzTOshsyqsbyMXnEfLUMRu94WHQ+yJTQSXwAKeXZGfSuTMiiyGJ3bSEDwy
|
||||
dCA7RW9QF58a6wVlW5s8xLZ+JxVx8QkyCkCsu7mFB6XJh3t8YZTMUC1EwH0Zy8y0
|
||||
JQeAw9A+I/XILoRhtOISM0vPrw9/TrKkKg8FGPAIE+fSTt6y7X5BWBqIE38u0wi7
|
||||
MyQZjmAhVz9nBkX6iggY9js/7Ix4LkCk6ERQoQxA0RWXcPX9LzBmisxL3nb86eYo
|
||||
o9f2fFtK9ErU7ZiYkb32U8/Jd205rrqWOxBhvQAcOqPsxVH5USi1I2gs912NVkXB
|
||||
dbb9dlEDIwiP+6E0EtEW/PodF8hzptbg8fjhu2G7l3f/ZLgBOvnyTJFHrgpRX7ce
|
||||
rK4SWkfGugRmgkD8S2Us0V1llpclJ6Baiw==
|
||||
-----END CERTIFICATE-----
|
@@ -1,4 +1,4 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFVjCCAz6gAwIBAgIEU71jgDANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNc3dhdEBtYWlsLmky
|
||||
|
@@ -1,23 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx
|
||||
DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL
|
||||
BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ
|
||||
ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV
|
||||
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu
|
||||
b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw
|
||||
ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m
|
||||
x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw
|
||||
vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+
|
||||
/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ
|
||||
KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv
|
||||
hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy
|
||||
qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A
|
||||
NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d
|
||||
PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
|
||||
Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG
|
||||
hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw
|
||||
DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr
|
||||
2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam
|
||||
X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn
|
||||
y6A=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx
|
||||
DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL
|
||||
BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ
|
||||
ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV
|
||||
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu
|
||||
b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw
|
||||
ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m
|
||||
x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw
|
||||
vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+
|
||||
/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ
|
||||
KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv
|
||||
hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy
|
||||
qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A
|
||||
NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d
|
||||
PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
|
||||
Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG
|
||||
hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw
|
||||
DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr
|
||||
2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam
|
||||
X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn
|
||||
y6A=
|
||||
-----END CERTIFICATE-----
|
||||
|
@@ -1,20 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB
|
||||
VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky
|
||||
UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw
|
||||
MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI
|
||||
EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL
|
||||
EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF
|
||||
XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ
|
||||
D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj
|
||||
Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi
|
||||
GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH
|
||||
mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB
|
||||
BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb
|
||||
B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z
|
||||
cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w
|
||||
wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9
|
||||
KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH
|
||||
Duud/n/w0kVV3DaIGikOsJayoanR+9HD
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB
|
||||
VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky
|
||||
UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw
|
||||
MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI
|
||||
EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL
|
||||
EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF
|
||||
XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ
|
||||
D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj
|
||||
Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi
|
||||
GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH
|
||||
mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB
|
||||
BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb
|
||||
B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z
|
||||
cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w
|
||||
wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9
|
||||
KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH
|
||||
Duud/n/w0kVV3DaIGikOsJayoanR+9HD
|
||||
-----END CERTIFICATE-----
|
||||
|
@@ -10,7 +10,7 @@
|
||||
<h1>I2P Anonymous Webserver</h1>
|
||||
<div class="langbar">
|
||||
<!-- Some of these languages listed here are yet to be translated -->
|
||||
<a href="index.html"><img src="lib/us.png" title="English" alt="English"></a
|
||||
<a href="index.html"><img src="lib/us.png" title="English" alt="English"></a>
|
||||
<a href="index_zh.html"><img src="lib/cn.png" title="中文" alt="中文"></a>
|
||||
<a href="index_de.html"><img src="lib/de.png" title="Deutsch" alt="Deutsch"></a>
|
||||
<a href="index_es.html"><img src="lib/es.png" title="Español" alt="Español"></a>
|
||||
|
@@ -314,6 +314,7 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
if (f.exists())
|
||||
SecureFileOutputStream.setPerms(f);
|
||||
}
|
||||
CryptoChecker.warnUnavailableCrypto(_context);
|
||||
|
||||
_routerInfo = null;
|
||||
_higherVersionSeen = false;
|
||||
|
@@ -18,10 +18,10 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 9;
|
||||
public final static long BUILD = 16;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
public final static String EXTRA = "-rc";
|
||||
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + FULL_VERSION);
|
||||
|
@@ -0,0 +1,249 @@
|
||||
package net.i2p.router.networkdb.kademlia;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import gnu.getopt.Getopt;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.RouterAddress;
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.router.transport.BadCountries;
|
||||
import net.i2p.router.transport.GeoIP;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
/**
|
||||
* Copy a random selection of 'count' router infos from configDir/netDb
|
||||
* to 'toDir'. Skip your own router info, and old, hidden, unreachable, and
|
||||
* introduced routers, and those from bad countries.
|
||||
*
|
||||
* Used in the build process.
|
||||
*
|
||||
* @since 0.9.15
|
||||
*
|
||||
*/
|
||||
public class BundleRouterInfos {
|
||||
|
||||
/**
|
||||
* Usage: PersistentDataStore -i configDir -o toDir -c count
|
||||
*
|
||||
* Copy a random selection of 'count' router infos from configDir/netDb
|
||||
* to 'toDir'. Skip your own router info, and old, hidden, unreachable, and
|
||||
* introduced routers, and those from bad countries.
|
||||
*
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Getopt g = new Getopt("PersistentDataStore", args, "i:o:c:");
|
||||
String in = System.getProperty("user.home") + "/.i2p";
|
||||
String out = "netDb";
|
||||
int count = 200;
|
||||
boolean error = false;
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
switch (c) {
|
||||
case 'i':
|
||||
in = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
out = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
String scount = g.getOptarg();
|
||||
try {
|
||||
count = Integer.parseInt(scount);
|
||||
} catch (NumberFormatException nfe) {
|
||||
error = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case ':':
|
||||
default:
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
usage();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Properties props = new Properties();
|
||||
props.setProperty(GeoIP.PROP_GEOIP_DIR, System.getProperty("user.dir") + "/installer/resources");
|
||||
GeoIP geoIP = new GeoIP(new I2PAppContext(props));
|
||||
|
||||
File confDir = new File(in);
|
||||
File dbDir = new File(confDir, "netDb");
|
||||
if (!dbDir.exists()) {
|
||||
System.out.println("NetDB directory " + dbDir + " does not exist");
|
||||
System.exit(1);
|
||||
}
|
||||
File myFile = new File(confDir, "router.info");
|
||||
File toDir = new File(out);
|
||||
toDir.mkdirs();
|
||||
InputStream fis = null;
|
||||
Hash me = null;
|
||||
try {
|
||||
fis = new BufferedInputStream(new FileInputStream(myFile));
|
||||
RouterInfo ri = new RouterInfo();
|
||||
ri.readBytes(fis, true); // true = verify sig on read
|
||||
me = ri.getIdentity().getHash();
|
||||
} catch (Exception e) {
|
||||
//System.out.println("Can't determine our identity");
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
int routerCount = 0;
|
||||
List<File> toRead = new ArrayList<File>(2048);
|
||||
for (int j = 0; j < PersistentDataStore.B64.length(); j++) {
|
||||
File subdir = new File(dbDir, PersistentDataStore.DIR_PREFIX + PersistentDataStore.B64.charAt(j));
|
||||
File[] files = subdir.listFiles(PersistentDataStore.RouterInfoFilter.getInstance());
|
||||
if (files == null)
|
||||
continue;
|
||||
routerCount += files.length;
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
toRead.add(files[i]);
|
||||
}
|
||||
}
|
||||
if (toRead.isEmpty()) {
|
||||
System.out.println("No files to copy in " + dbDir);
|
||||
System.exit(1);
|
||||
}
|
||||
Collections.shuffle(toRead);
|
||||
int copied = 0;
|
||||
long tooOld = System.currentTimeMillis() - 7*24*60*60*1000L;
|
||||
Map<String, String> ipMap = new HashMap<String, String>(count);
|
||||
for (File file : toRead) {
|
||||
if (copied >= count)
|
||||
break;
|
||||
Hash key = PersistentDataStore.getRouterInfoHash(file.getName());
|
||||
if (key == null) {
|
||||
System.out.println("Skipping bad " + file);
|
||||
continue;
|
||||
}
|
||||
if (key.equals(me)) {
|
||||
System.out.println("Skipping my RI");
|
||||
continue;
|
||||
}
|
||||
fis = null;
|
||||
try {
|
||||
fis = new BufferedInputStream(new FileInputStream(file));
|
||||
RouterInfo ri = new RouterInfo();
|
||||
ri.readBytes(fis, true); // true = verify sig on read
|
||||
try { fis.close(); } catch (IOException ioe) {}
|
||||
fis = null;
|
||||
if (ri.getPublished() < tooOld) {
|
||||
System.out.println("Skipping too old " + key);
|
||||
continue;
|
||||
}
|
||||
if (ri.getCapabilities().contains("U")) {
|
||||
System.out.println("Skipping unreachable " + key);
|
||||
continue;
|
||||
}
|
||||
if (ri.getCapabilities().contains("K")) {
|
||||
System.out.println("Skipping slow " + key);
|
||||
continue;
|
||||
}
|
||||
Collection<RouterAddress> addrs = ri.getAddresses();
|
||||
if (addrs.isEmpty()) {
|
||||
System.out.println("Skipping hidden " + key);
|
||||
continue;
|
||||
}
|
||||
boolean hasIntro = false;
|
||||
boolean hasIPv4 = false;
|
||||
boolean dupIP = false;
|
||||
for (RouterAddress addr : addrs) {
|
||||
if ("SSU".equals(addr.getTransportStyle()) && addr.getOption("ihost0") != null) {
|
||||
hasIntro = true;
|
||||
break;
|
||||
}
|
||||
String host = addr.getHost();
|
||||
if (host != null && host.contains(".")) {
|
||||
hasIPv4 = true;
|
||||
geoIP.add(host);
|
||||
String old = ipMap.put(host, file.getName());
|
||||
if (old != null && !old.equals(file.getName())) {
|
||||
dupIP = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dupIP) {
|
||||
System.out.println("Skipping dup IP " + key);
|
||||
continue;
|
||||
}
|
||||
if (hasIntro) {
|
||||
System.out.println("Skipping introduced " + key);
|
||||
continue;
|
||||
}
|
||||
if (!hasIPv4) {
|
||||
System.out.println("Skipping IPv6-only " + key);
|
||||
continue;
|
||||
}
|
||||
File toFile = new File(toDir, file.getName());
|
||||
// We could call ri.write() to avoid simultaneous change by the router
|
||||
boolean ok = FileUtil.copy(file, toFile, true, true);
|
||||
if (ok)
|
||||
copied++;
|
||||
else
|
||||
System.out.println("Failed copy of " + file + " to " + toDir);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Skipping bad " + file);
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
if (copied > 0) {
|
||||
// now do all the geoip lookups, and delete any bad countries
|
||||
geoIP.blockingLookup();
|
||||
for (Map.Entry<String, String> e : ipMap.entrySet()) {
|
||||
String co = geoIP.get(e.getKey());
|
||||
if (co != null) {
|
||||
if (BadCountries.contains(co)) {
|
||||
String name = e.getValue();
|
||||
File toFile = new File(toDir, name);
|
||||
if (toFile.delete()) {
|
||||
String full = geoIP.fullName(co);
|
||||
if (full == null)
|
||||
full = co;
|
||||
System.out.println("Skipping " + full + ": " + name);
|
||||
copied--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (copied > 0) {
|
||||
System.out.println("Copied " + copied + " router info files to " + toDir);
|
||||
} else {
|
||||
System.out.println("Failed to copy any files to " + toDir);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.err.println("Usage: PersistentDataStore [-i $HOME/.i2p] [-o netDb/] [-c 200]");
|
||||
}
|
||||
}
|
@@ -54,8 +54,8 @@ class PersistentDataStore extends TransientDataStore {
|
||||
|
||||
private final static int READ_DELAY = 2*60*1000;
|
||||
private static final String PROP_FLAT = "router.networkDatabase.flat";
|
||||
private static final String DIR_PREFIX = "r";
|
||||
private static final String B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~";
|
||||
static final String DIR_PREFIX = "r";
|
||||
static final String B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~";
|
||||
|
||||
/**
|
||||
* @param dbDir relative path
|
||||
@@ -614,7 +614,7 @@ class PersistentDataStore extends TransientDataStore {
|
||||
return DIR_PREFIX + b64.charAt(0) + File.separatorChar + ROUTERINFO_PREFIX + b64 + ROUTERINFO_SUFFIX;
|
||||
}
|
||||
|
||||
private static Hash getRouterInfoHash(String filename) {
|
||||
static Hash getRouterInfoHash(String filename) {
|
||||
return getHash(filename, ROUTERINFO_PREFIX, ROUTERINFO_SUFFIX);
|
||||
}
|
||||
|
||||
@@ -651,7 +651,7 @@ class PersistentDataStore extends TransientDataStore {
|
||||
}
|
||||
}
|
||||
|
||||
private final static class RouterInfoFilter implements FilenameFilter {
|
||||
static class RouterInfoFilter implements FilenameFilter {
|
||||
private static final FilenameFilter _instance = new RouterInfoFilter();
|
||||
public static final FilenameFilter getInstance() { return _instance; }
|
||||
public boolean accept(File dir, String name) {
|
||||
|
@@ -74,8 +74,7 @@ public class Reseeder {
|
||||
"http://reseed.i2p-projekt.de/" + "," +
|
||||
//"http://euve5653.vserver.de/netDb/" + "," +
|
||||
"http://cowpuncher.drollette.com/netdb/" + "," +
|
||||
//Temp disabled (#1351)
|
||||
//"http://i2p.mooo.com/netDb/" + "," +
|
||||
"http://i2p.mooo.com/netDb/" + "," +
|
||||
"http://193.150.121.66/netDb/" + "," +
|
||||
"http://netdb.i2p2.no/" + "," +
|
||||
"http://reseed.info/" + "," +
|
||||
@@ -93,8 +92,7 @@ public class Reseeder {
|
||||
"https://reseed.i2p-projekt.de/" + "," +
|
||||
//"https://euve5653.vserver.de/netDb/" + "," +
|
||||
"https://cowpuncher.drollette.com/netdb/" + "," +
|
||||
//Temp disabled (#1351)
|
||||
//"https://i2p.mooo.com/netDb/" + "," +
|
||||
"https://i2p.mooo.com/netDb/" + "," +
|
||||
"https://193.150.121.66/netDb/" + "," +
|
||||
"https://netdb.i2p2.no/" + "," +
|
||||
"https://reseed.info/" + "," +
|
||||
|
@@ -271,6 +271,8 @@ public class WorkingDir {
|
||||
// We don't currently have a default addressbook/ in the base distribution,
|
||||
// but distros might put one in
|
||||
"addressbook,eepsite," +
|
||||
// 0.9.15 support bundled router infos
|
||||
"netDb," +
|
||||
// base install - files
|
||||
// We don't currently have a default router.config, logger.config, susimail.config, or webapps.config in the base distribution,
|
||||
// but distros might put one in
|
||||
|
101
router/java/src/net/i2p/router/tasks/CryptoChecker.java
Normal file
101
router/java/src/net/i2p/router/tasks/CryptoChecker.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package net.i2p.router.tasks;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* Warn about unavailable crypto to router and wrapper logs
|
||||
*
|
||||
* @since 0.9.15
|
||||
*/
|
||||
public class CryptoChecker {
|
||||
|
||||
private static String JRE6 = "http://www.oracle.com/technetwork/java/javase/downloads/index.html";
|
||||
// these two are US-only and can change?
|
||||
//private static String JRE7 = "http://www.oracle.com/technetwork/java/javase/documentation/java-se-7-doc-download-435117.html";
|
||||
//private static String JRE8 = "http://www.oracle.com/technetwork/java/javase/documentation/jdk8-doc-downloads-2133158.html";
|
||||
|
||||
/**
|
||||
* @param ctx if null, logs only to System.out (called from main)
|
||||
*/
|
||||
public static void warnUnavailableCrypto(RouterContext ctx) {
|
||||
if (SystemVersion.isAndroid())
|
||||
return;
|
||||
boolean unavail = false;
|
||||
Log log = null;
|
||||
for (SigType t : SigType.values()) {
|
||||
if (!t.isAvailable()) {
|
||||
if (!unavail) {
|
||||
unavail = true;
|
||||
if (ctx != null)
|
||||
log = ctx.logManager().getLog(CryptoChecker.class);
|
||||
}
|
||||
String s = "Crypto " + t + " is not available";
|
||||
if (log != null)
|
||||
log.logAlways(log.WARN, s);
|
||||
System.out.println("Warning: " + s);
|
||||
}
|
||||
}
|
||||
if (unavail) {
|
||||
if (!SystemVersion.isJava7()) {
|
||||
String s = "Java version: " + System.getProperty("java.version") + " Please consider upgrading to Java 7";
|
||||
if (log != null)
|
||||
log.logAlways(log.WARN, s);
|
||||
System.out.println(s);
|
||||
}
|
||||
if (!isUnlimited()) {
|
||||
String s = "Please consider installing the Java Cryptography Unlimited Strength Jurisdiction Policy Files from ";
|
||||
//if (SystemVersion.isJava8())
|
||||
// s += JRE8;
|
||||
//else if (SystemVersion.isJava7())
|
||||
// s += JRE7;
|
||||
//else
|
||||
s += JRE6;
|
||||
if (log != null)
|
||||
log.logAlways(log.WARN, s);
|
||||
System.out.println(s);
|
||||
}
|
||||
String s = "This crypto will be required in a future release";
|
||||
if (log != null)
|
||||
log.logAlways(log.WARN, s);
|
||||
System.out.println("Warning: " + s);
|
||||
} else if (ctx == null) {
|
||||
// called from main()
|
||||
System.out.println("All crypto available");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from CryptixAESEngine
|
||||
*/
|
||||
private static boolean isUnlimited() {
|
||||
try {
|
||||
if (Cipher.getMaxAllowedKeyLength("AES") < 256)
|
||||
return false;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return false;
|
||||
} catch (NoSuchMethodError e) {
|
||||
// JamVM, gij
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
warnUnavailableCrypto(null);
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ import java.util.Set;
|
||||
* Maintain a list of bad places.
|
||||
* @since 0.8.13
|
||||
*/
|
||||
abstract class BadCountries {
|
||||
public abstract class BadCountries {
|
||||
|
||||
private static final Set<String> _countries;
|
||||
|
||||
|
@@ -16,6 +16,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
@@ -38,11 +39,9 @@ import net.i2p.util.Log;
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
class GeoIP {
|
||||
public class GeoIP {
|
||||
private final Log _log;
|
||||
// change to test with main()
|
||||
//private final I2PAppContext _context;
|
||||
private final RouterContext _context;
|
||||
private final I2PAppContext _context;
|
||||
private final Map<String, String> _codeToName;
|
||||
/** code to itself to prevent String proliferation */
|
||||
private final Map<String, String> _codeCache;
|
||||
@@ -56,8 +55,10 @@ class GeoIP {
|
||||
private final AtomicBoolean _lock;
|
||||
private int _lookupRunCount;
|
||||
|
||||
//public GeoIP(I2PAppContext context) {
|
||||
public GeoIP(RouterContext context) {
|
||||
/**
|
||||
* @param context RouterContext in production, I2PAppContext for testing only
|
||||
*/
|
||||
public GeoIP(I2PAppContext context) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(GeoIP.class);
|
||||
_codeToName = new ConcurrentHashMap<String, String>(512);
|
||||
@@ -71,6 +72,7 @@ class GeoIP {
|
||||
}
|
||||
|
||||
static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
|
||||
public static final String PROP_GEOIP_DIR = "geoip.dir";
|
||||
static final String GEOIP_DIR_DEFAULT = "geoip";
|
||||
static final String GEOIP_FILE_DEFAULT = "geoip.txt";
|
||||
static final String COUNTRY_FILE_DEFAULT = "countries.txt";
|
||||
@@ -187,7 +189,10 @@ class GeoIP {
|
||||
*
|
||||
*/
|
||||
private void readCountryFile() {
|
||||
File geoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
|
||||
String geoDir = _context.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
|
||||
File geoFile = new File(geoDir);
|
||||
if (!geoFile.isAbsolute())
|
||||
geoFile = new File(_context.getBaseDir(), geoDir);
|
||||
geoFile = new File(geoFile, COUNTRY_FILE_DEFAULT);
|
||||
if (!geoFile.exists()) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -246,7 +251,10 @@ class GeoIP {
|
||||
*
|
||||
*/
|
||||
private String[] readGeoIPFile(Long[] search) {
|
||||
File geoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
|
||||
String geoDir = _context.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
|
||||
File geoFile = new File(geoDir);
|
||||
if (!geoFile.isAbsolute())
|
||||
geoFile = new File(_context.getBaseDir(), geoDir);
|
||||
geoFile = new File(geoFile, GEOIP_FILE_DEFAULT);
|
||||
if (!geoFile.exists()) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -300,24 +308,28 @@ class GeoIP {
|
||||
/**
|
||||
* Put our country code in the config, where others (such as Timestamper) can get it,
|
||||
* and it will be there next time at startup.
|
||||
*
|
||||
* Does nothing in I2PAppContext
|
||||
*/
|
||||
private void updateOurCountry() {
|
||||
/**** comment out to test with main() */
|
||||
String oldCountry = _context.router().getConfigSetting(PROP_IP_COUNTRY);
|
||||
Hash ourHash = _context.routerHash();
|
||||
if (! (_context instanceof RouterContext))
|
||||
return;
|
||||
RouterContext ctx = (RouterContext) _context;
|
||||
String oldCountry = ctx.router().getConfigSetting(PROP_IP_COUNTRY);
|
||||
Hash ourHash = ctx.routerHash();
|
||||
// we should always have a RouterInfo by now, but we had one report of an NPE here
|
||||
if (ourHash == null)
|
||||
return;
|
||||
String country = _context.commSystem().getCountry(ourHash);
|
||||
String country = ctx.commSystem().getCountry(ourHash);
|
||||
if (country != null && !country.equals(oldCountry)) {
|
||||
_context.router().saveConfig(PROP_IP_COUNTRY, country);
|
||||
if (_context.commSystem().isInBadCountry() && _context.getProperty(Router.PROP_HIDDEN_HIDDEN) == null) {
|
||||
ctx.router().saveConfig(PROP_IP_COUNTRY, country);
|
||||
if (ctx.commSystem().isInBadCountry() && ctx.getProperty(Router.PROP_HIDDEN_HIDDEN) == null) {
|
||||
String name = fullName(country);
|
||||
if (name == null)
|
||||
name = country;
|
||||
_log.logAlways(Log.WARN, "Setting hidden mode to protect you in " + name +
|
||||
", you may override on the network configuration page");
|
||||
_context.router().rebuildRouterInfo();
|
||||
ctx.router().rebuildRouterInfo();
|
||||
}
|
||||
}
|
||||
/****/
|
||||
|
@@ -292,7 +292,14 @@ public class ControlPoint implements HTTPRequestListener
|
||||
DeviceList devList = new DeviceList();
|
||||
int nRoots = devNodeList.size();
|
||||
for (int n=0; n<nRoots; n++) {
|
||||
Node rootNode = devNodeList.getNode(n);
|
||||
// AIOOB was thrown from here, maybe would be better to
|
||||
// copy the list before traversal?
|
||||
Node rootNode;
|
||||
try {
|
||||
rootNode = devNodeList.getNode(n);
|
||||
} catch (ArrayIndexOutOfBoundsException aioob) {
|
||||
break;
|
||||
}
|
||||
Device dev = getDevice(rootNode);
|
||||
if (dev == null)
|
||||
continue;
|
||||
|
@@ -164,6 +164,14 @@ do
|
||||
else
|
||||
compute_dates
|
||||
fi
|
||||
if grep '\s$' $i > /dev/null 2>&1; then
|
||||
echo "********* Trailing whitespace found in file $i *********"
|
||||
FAIL=1
|
||||
fi
|
||||
if grep '^\s' $i > /dev/null 2>&1; then
|
||||
echo "********* Leading whitespace found in file $i *********"
|
||||
FAIL=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$FAIL" ]; then
|
||||
|
Reference in New Issue
Block a user