propagate from branch 'i2p.i2p.zzz.test2' (head 6ccd9ca652057494bb2857e87636f18aadcd33f3)
to branch 'i2p.i2p' (head 376f751adc13923cdbf4f659c3f23ca957cf47b3)
@@ -182,7 +182,7 @@ Applications:
|
|||||||
By welterde.
|
By welterde.
|
||||||
See licenses/LICENSE-GPLv2.txt
|
See licenses/LICENSE-GPLv2.txt
|
||||||
|
|
||||||
Jetty 8.1.15.v20140411:
|
Jetty 8.1.16.v20140903:
|
||||||
See licenses/ABOUT-Jetty.html
|
See licenses/ABOUT-Jetty.html
|
||||||
See licenses/NOTICE-Jetty.html
|
See licenses/NOTICE-Jetty.html
|
||||||
See licenses/LICENSE-Apache2.0.txt
|
See licenses/LICENSE-Apache2.0.txt
|
||||||
|
@@ -64,10 +64,11 @@ class ConfigParser {
|
|||||||
if (inputLine.startsWith(";")) {
|
if (inputLine.startsWith(";")) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if (inputLine.split("#").length > 0) {
|
int hash = inputLine.indexOf('#');
|
||||||
return inputLine.split("#")[0];
|
if (hash >= 0) {
|
||||||
|
return inputLine.substring(0, hash);
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return inputLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -100,15 +100,15 @@
|
|||||||
<target name="war" depends="jar, bundle, warUpToDate, listChangedFiles" unless="war.uptodate" >
|
<target name="war" depends="jar, bundle, warUpToDate, listChangedFiles" unless="war.uptodate" >
|
||||||
<!-- set if unset -->
|
<!-- set if unset -->
|
||||||
<property name="workspace.changes.tr" value="" />
|
<property name="workspace.changes.tr" value="" />
|
||||||
<copy todir="build/icons/.icons" >
|
<copy todir="build/resources/.resources" >
|
||||||
<fileset dir="../icons/" />
|
<fileset dir="../resources/" />
|
||||||
</copy>
|
</copy>
|
||||||
<!-- mime.properties must be in with the classes -->
|
<!-- mime.properties must be in with the classes -->
|
||||||
<copy file="../mime.properties" todir="build/obj/org/klomp/snark/web" />
|
<copy file="../mime.properties" todir="build/obj/org/klomp/snark/web" />
|
||||||
<war destfile="../i2psnark.war" webxml="../web.xml" >
|
<war destfile="../i2psnark.war" webxml="../web.xml" >
|
||||||
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
|
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
|
||||||
<classes dir="./build/obj" includes="**/web/*" />
|
<classes dir="./build/obj" includes="**/web/*" />
|
||||||
<fileset dir="build/icons/" />
|
<fileset dir="build/resources/" />
|
||||||
<manifest>
|
<manifest>
|
||||||
<attribute name="Implementation-Version" value="${full.version}" />
|
<attribute name="Implementation-Version" value="${full.version}" />
|
||||||
<attribute name="Built-By" value="${build.built-by}" />
|
<attribute name="Built-By" value="${build.built-by}" />
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
|
|
||||||
<target name="warUpToDate">
|
<target name="warUpToDate">
|
||||||
<uptodate property="war.uptodate" targetfile="../i2psnark.war" >
|
<uptodate property="war.uptodate" targetfile="../i2psnark.war" >
|
||||||
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../icons/* ../web.xml" />
|
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../resources/**/* ../web.xml" />
|
||||||
</uptodate>
|
</uptodate>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
@@ -57,8 +57,8 @@ public class Peer implements Comparable<Peer>
|
|||||||
private DataOutputStream dout;
|
private DataOutputStream dout;
|
||||||
|
|
||||||
/** running counters */
|
/** running counters */
|
||||||
private long downloaded;
|
private final AtomicLong downloaded = new AtomicLong();
|
||||||
private long uploaded;
|
private final AtomicLong uploaded = new AtomicLong();
|
||||||
|
|
||||||
// Keeps state for in/out connections. Non-null when the handshake
|
// Keeps state for in/out connections. Non-null when the handshake
|
||||||
// was successful, the connection setup and runs
|
// was successful, the connection setup and runs
|
||||||
@@ -618,7 +618,7 @@ public class Peer implements Comparable<Peer>
|
|||||||
* @since 0.8.4
|
* @since 0.8.4
|
||||||
*/
|
*/
|
||||||
public void downloaded(int size) {
|
public void downloaded(int size) {
|
||||||
downloaded += size;
|
downloaded.addAndGet(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -626,7 +626,7 @@ public class Peer implements Comparable<Peer>
|
|||||||
* @since 0.8.4
|
* @since 0.8.4
|
||||||
*/
|
*/
|
||||||
public void uploaded(int size) {
|
public void uploaded(int size) {
|
||||||
uploaded += size;
|
uploaded.addAndGet(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -635,7 +635,7 @@ public class Peer implements Comparable<Peer>
|
|||||||
*/
|
*/
|
||||||
public long getDownloaded()
|
public long getDownloaded()
|
||||||
{
|
{
|
||||||
return downloaded;
|
return downloaded.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -644,7 +644,7 @@ public class Peer implements Comparable<Peer>
|
|||||||
*/
|
*/
|
||||||
public long getUploaded()
|
public long getUploaded()
|
||||||
{
|
{
|
||||||
return uploaded;
|
return uploaded.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -652,8 +652,8 @@ public class Peer implements Comparable<Peer>
|
|||||||
*/
|
*/
|
||||||
public void resetCounters()
|
public void resetCounters()
|
||||||
{
|
{
|
||||||
downloaded = 0;
|
downloaded.set(0);
|
||||||
uploaded = 0;
|
uploaded.set(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getInactiveTime() {
|
public long getInactiveTime() {
|
||||||
|
@@ -27,7 +27,6 @@ import java.io.InputStream;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
@@ -245,16 +244,19 @@ public class Snark
|
|||||||
*
|
*
|
||||||
* @deprecated unused
|
* @deprecated unused
|
||||||
*/
|
*/
|
||||||
|
/****
|
||||||
Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
|
Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
|
||||||
StorageListener slistener, CoordinatorListener clistener) {
|
StorageListener slistener, CoordinatorListener clistener) {
|
||||||
this(util, torrent, ip, user_port, slistener, clistener, null, null, null, true, ".");
|
this(util, torrent, ip, user_port, slistener, clistener, null, null, null, true, ".");
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* single torrent - via router
|
* single torrent - via router
|
||||||
*
|
*
|
||||||
* @deprecated unused
|
* @deprecated unused
|
||||||
*/
|
*/
|
||||||
|
/****
|
||||||
public Snark(I2PAppContext ctx, Properties opts, String torrent,
|
public Snark(I2PAppContext ctx, Properties opts, String torrent,
|
||||||
StorageListener slistener, boolean start, String rootDir) {
|
StorageListener slistener, boolean start, String rootDir) {
|
||||||
this(new I2PSnarkUtil(ctx), torrent, null, -1, slistener, null, null, null, null, false, rootDir);
|
this(new I2PSnarkUtil(ctx), torrent, null, -1, slistener, null, null, null, null, false, rootDir);
|
||||||
@@ -284,6 +286,7 @@ public class Snark
|
|||||||
if (start)
|
if (start)
|
||||||
this.startTorrent();
|
this.startTorrent();
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* multitorrent
|
* multitorrent
|
||||||
@@ -515,18 +518,13 @@ public class Snark
|
|||||||
|
|
||||||
// Create a new ID and fill it with something random. First nine
|
// Create a new ID and fill it with something random. First nine
|
||||||
// zeros bytes, then three bytes filled with snark and then
|
// zeros bytes, then three bytes filled with snark and then
|
||||||
// sixteen random bytes.
|
// eight random bytes.
|
||||||
byte snark = (((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
|
byte snark = (((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
|
||||||
byte[] rv = new byte[20];
|
byte[] rv = new byte[20];
|
||||||
Random random = I2PAppContext.getGlobalContext().random();
|
rv[9] = snark;
|
||||||
int i;
|
rv[10] = snark;
|
||||||
for (i = 0; i < 9; i++)
|
rv[11] = snark;
|
||||||
rv[i] = 0;
|
I2PAppContext.getGlobalContext().random().nextBytes(rv, 12, 8);
|
||||||
rv[i++] = snark;
|
|
||||||
rv[i++] = snark;
|
|
||||||
rv[i++] = snark;
|
|
||||||
while (i < 20)
|
|
||||||
rv[i++] = (byte)random.nextInt(256);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,6 +956,7 @@ public class Snark
|
|||||||
* non-valid argument list. The given listeners will be
|
* non-valid argument list. The given listeners will be
|
||||||
* passed to all components that take one.
|
* passed to all components that take one.
|
||||||
*/
|
*/
|
||||||
|
/****
|
||||||
private static Snark parseArguments(String[] args,
|
private static Snark parseArguments(String[] args,
|
||||||
StorageListener slistener,
|
StorageListener slistener,
|
||||||
CoordinatorListener clistener)
|
CoordinatorListener clistener)
|
||||||
@@ -972,6 +971,7 @@ public class Snark
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < args.length)
|
while (i < args.length)
|
||||||
{
|
{
|
||||||
|
****/
|
||||||
/*
|
/*
|
||||||
if (args[i].equals("--debug"))
|
if (args[i].equals("--debug"))
|
||||||
{
|
{
|
||||||
@@ -993,7 +993,9 @@ public class Snark
|
|||||||
catch (NumberFormatException nfe) { }
|
catch (NumberFormatException nfe) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else */ if (args[i].equals("--port"))
|
else */
|
||||||
|
/****
|
||||||
|
if (args[i].equals("--port"))
|
||||||
{
|
{
|
||||||
if (args.length - 1 < i + 1)
|
if (args.length - 1 < i + 1)
|
||||||
usage("--port needs port number to listen on");
|
usage("--port needs port number to listen on");
|
||||||
@@ -1099,6 +1101,7 @@ public class Snark
|
|||||||
System.out.println
|
System.out.println
|
||||||
(" \tor (with --share) a file to share.");
|
(" \tor (with --share) a file to share.");
|
||||||
}
|
}
|
||||||
|
****/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aborts program abnormally.
|
* Aborts program abnormally.
|
||||||
|
@@ -600,10 +600,10 @@ public class SnarkManager implements CompleteListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all themes
|
* Get all themes
|
||||||
* @return String[] -- Array of all the themes found.
|
* @return String[] -- Array of all the themes found, non-null, unsorted
|
||||||
*/
|
*/
|
||||||
public String[] getThemes() {
|
public String[] getThemes() {
|
||||||
String[] themes = null;
|
String[] themes;
|
||||||
// "docs/themes/snark/"
|
// "docs/themes/snark/"
|
||||||
File dir = new File(_context.getBaseDir(), "docs/themes/snark");
|
File dir = new File(_context.getBaseDir(), "docs/themes/snark");
|
||||||
FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } };
|
FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } };
|
||||||
@@ -614,6 +614,8 @@ public class SnarkManager implements CompleteListener {
|
|||||||
for(int i = 0; i < dirnames.length; i++) {
|
for(int i = 0; i < dirnames.length; i++) {
|
||||||
themes[i] = dirnames[i].getName();
|
themes[i] = dirnames[i].getName();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
themes = new String[0];
|
||||||
}
|
}
|
||||||
// return the map.
|
// return the map.
|
||||||
return themes;
|
return themes;
|
||||||
|
531
apps/i2psnark/java/src/org/klomp/snark/web/Sorters.java
Normal file
@@ -0,0 +1,531 @@
|
|||||||
|
package org.klomp.snark.web;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.text.Collator;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.klomp.snark.MetaInfo;
|
||||||
|
import org.klomp.snark.Snark;
|
||||||
|
import org.klomp.snark.Storage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparators for various columns
|
||||||
|
*
|
||||||
|
* @since 0.9.16 from TorrentNameComparator, moved from I2PSnarkservlet
|
||||||
|
*/
|
||||||
|
class Sorters {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negative is reverse
|
||||||
|
*
|
||||||
|
*<ul>
|
||||||
|
*<li>0, 1: Name
|
||||||
|
*<li>2: Status
|
||||||
|
*<li>3: Peers
|
||||||
|
*<li>4: ETA
|
||||||
|
*<li>5: Size
|
||||||
|
*<li>6: Downloaded
|
||||||
|
*<li>7: Uploaded
|
||||||
|
*<li>8: Down rate
|
||||||
|
*<li>9: Up rate
|
||||||
|
*<li>10: Remaining (needed)
|
||||||
|
*<li>11: Upload ratio
|
||||||
|
*<li>12: File type
|
||||||
|
*</ul>
|
||||||
|
*
|
||||||
|
* @param servlet for file type callback only
|
||||||
|
*/
|
||||||
|
public static Comparator<Snark> getComparator(int type, I2PSnarkServlet servlet) {
|
||||||
|
boolean rev = type < 0;
|
||||||
|
Comparator<Snark> rv;
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
rv = new TorrentNameComparator();
|
||||||
|
if (rev)
|
||||||
|
rv = Collections.reverseOrder(rv);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -2:
|
||||||
|
case 2:
|
||||||
|
rv = new StatusComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -3:
|
||||||
|
case 3:
|
||||||
|
rv = new PeersComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -4:
|
||||||
|
case 4:
|
||||||
|
rv = new ETAComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -5:
|
||||||
|
case 5:
|
||||||
|
rv = new SizeComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -6:
|
||||||
|
case 6:
|
||||||
|
rv = new DownloadedComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -7:
|
||||||
|
case 7:
|
||||||
|
rv = new UploadedComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -8:
|
||||||
|
case 8:
|
||||||
|
rv = new DownRateComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -9:
|
||||||
|
case 9:
|
||||||
|
rv = new UpRateComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -10:
|
||||||
|
case 10:
|
||||||
|
rv = new RemainingComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -11:
|
||||||
|
case 11:
|
||||||
|
rv = new RatioComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -12:
|
||||||
|
case 12:
|
||||||
|
rv = new FileTypeComparator(rev, servlet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort alphabetically in current locale, ignore case, ignore leading "the "
|
||||||
|
* (I guess this is worth it, a lot of torrents start with "The "
|
||||||
|
* @since 0.7.14
|
||||||
|
*/
|
||||||
|
private static class TorrentNameComparator implements Comparator<Snark>, Serializable {
|
||||||
|
|
||||||
|
public int compare(Snark l, Snark r) {
|
||||||
|
return comp(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int comp(Snark l, Snark r) {
|
||||||
|
// put downloads and magnets first
|
||||||
|
if (l.getStorage() == null && r.getStorage() != null)
|
||||||
|
return -1;
|
||||||
|
if (l.getStorage() != null && r.getStorage() == null)
|
||||||
|
return 1;
|
||||||
|
String ls = l.getBaseName();
|
||||||
|
String llc = ls.toLowerCase(Locale.US);
|
||||||
|
if (llc.startsWith("the ") || llc.startsWith("the.") || llc.startsWith("the_"))
|
||||||
|
ls = ls.substring(4);
|
||||||
|
String rs = r.getBaseName();
|
||||||
|
String rlc = rs.toLowerCase(Locale.US);
|
||||||
|
if (rlc.startsWith("the ") || rlc.startsWith("the.") || rlc.startsWith("the_"))
|
||||||
|
rs = rs.substring(4);
|
||||||
|
return Collator.getInstance().compare(ls, rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward or reverse sort, but the fallback is always forward
|
||||||
|
*/
|
||||||
|
private static abstract class Sort implements Comparator<Snark>, Serializable {
|
||||||
|
|
||||||
|
private final boolean _rev;
|
||||||
|
|
||||||
|
public Sort(boolean rev) {
|
||||||
|
_rev = rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(Snark l, Snark r) {
|
||||||
|
int rv = compareIt(l, r);
|
||||||
|
if (rv != 0)
|
||||||
|
return _rev ? 0 - rv : rv;
|
||||||
|
return TorrentNameComparator.comp(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int compareIt(Snark l, Snark r);
|
||||||
|
|
||||||
|
protected static int compLong(long l, long r) {
|
||||||
|
if (l < r)
|
||||||
|
return -1;
|
||||||
|
if (l > r)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class StatusComparator extends Sort {
|
||||||
|
|
||||||
|
private StatusComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
int rv = getStatus(l) - getStatus(r);
|
||||||
|
if (rv != 0)
|
||||||
|
return rv;
|
||||||
|
// use reverse remaining as first tie break
|
||||||
|
return compLong(r.getNeededLength(), l.getNeededLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getStatus(Snark snark) {
|
||||||
|
long remaining = snark.getRemainingLength();
|
||||||
|
long needed = snark.getNeededLength();
|
||||||
|
if (snark.isStopped()) {
|
||||||
|
if (remaining < 0)
|
||||||
|
return 0;
|
||||||
|
if (remaining > 0)
|
||||||
|
return 5;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
if (snark.isStarting())
|
||||||
|
return 15;
|
||||||
|
if (snark.isAllocating())
|
||||||
|
return 20;
|
||||||
|
if (remaining < 0)
|
||||||
|
return 15; // magnet
|
||||||
|
if (remaining == 0)
|
||||||
|
return 100;
|
||||||
|
if (snark.isChecking())
|
||||||
|
return 95;
|
||||||
|
if (snark.getNeededLength() <= 0)
|
||||||
|
return 90;
|
||||||
|
if (snark.getPeerCount() <= 0)
|
||||||
|
return 40;
|
||||||
|
if (snark.getDownloadRate() <= 0)
|
||||||
|
return 50;
|
||||||
|
return 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PeersComparator extends Sort {
|
||||||
|
|
||||||
|
public PeersComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return l.getPeerCount() - r.getPeerCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RemainingComparator extends Sort {
|
||||||
|
|
||||||
|
public RemainingComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return compLong(l.getNeededLength(), r.getNeededLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ETAComparator extends Sort {
|
||||||
|
|
||||||
|
public ETAComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return compLong(eta(l), eta(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long eta(Snark snark) {
|
||||||
|
long needed = snark.getNeededLength();
|
||||||
|
if (needed <= 0)
|
||||||
|
return 0;
|
||||||
|
long total = snark.getTotalLength();
|
||||||
|
if (needed > total)
|
||||||
|
needed = total;
|
||||||
|
long downBps = snark.getDownloadRate();
|
||||||
|
if (downBps > 0)
|
||||||
|
return needed / downBps;
|
||||||
|
return Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SizeComparator extends Sort {
|
||||||
|
|
||||||
|
public SizeComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return compLong(l.getTotalLength(), r.getTotalLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DownloadedComparator extends Sort {
|
||||||
|
|
||||||
|
public DownloadedComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
long ld = l.getTotalLength() - l.getRemainingLength();
|
||||||
|
long rd = r.getTotalLength() - r.getRemainingLength();
|
||||||
|
return compLong(ld, rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UploadedComparator extends Sort {
|
||||||
|
|
||||||
|
public UploadedComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return compLong(l.getUploaded(), r.getUploaded());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DownRateComparator extends Sort {
|
||||||
|
|
||||||
|
public DownRateComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return compLong(l.getDownloadRate(), r.getDownloadRate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UpRateComparator extends Sort {
|
||||||
|
|
||||||
|
public UpRateComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
return compLong(l.getUploadRate(), r.getUploadRate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RatioComparator extends Sort {
|
||||||
|
|
||||||
|
private static final long M = 128 * 1024 * 1024;
|
||||||
|
|
||||||
|
public RatioComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
long lt = l.getTotalLength();
|
||||||
|
long ld = lt > 0 ? ((M * l.getUploaded()) / lt) : 0;
|
||||||
|
long rt = r.getTotalLength();
|
||||||
|
long rd = rt > 0 ? ((M * r.getUploaded()) / rt) : 0;
|
||||||
|
return compLong(ld, rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FileTypeComparator extends Sort {
|
||||||
|
|
||||||
|
private final I2PSnarkServlet servlet;
|
||||||
|
|
||||||
|
public FileTypeComparator(boolean rev, I2PSnarkServlet servlet) {
|
||||||
|
super(rev);
|
||||||
|
this.servlet = servlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareIt(Snark l, Snark r) {
|
||||||
|
String ls = toName(l);
|
||||||
|
String rs = toName(r);
|
||||||
|
return ls.compareTo(rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toName(Snark snark) {
|
||||||
|
MetaInfo meta = snark.getMetaInfo();
|
||||||
|
if (meta == null)
|
||||||
|
return "0";
|
||||||
|
if (meta.getFiles() != null)
|
||||||
|
return "1";
|
||||||
|
// arbitrary sort based on icon name
|
||||||
|
return servlet.toIcon(meta.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////// Comparators for details page below
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to precompute and efficiently sort data
|
||||||
|
* on a torrent file entry.
|
||||||
|
*/
|
||||||
|
public static class FileAndIndex {
|
||||||
|
public final File file;
|
||||||
|
public final boolean isDirectory;
|
||||||
|
public final long length;
|
||||||
|
public final long remaining;
|
||||||
|
public final int priority;
|
||||||
|
public final int index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param storage may be null
|
||||||
|
*/
|
||||||
|
public FileAndIndex(File file, Storage storage) {
|
||||||
|
this.file = file;
|
||||||
|
index = storage != null ? storage.indexOf(file) : -1;
|
||||||
|
if (index >= 0) {
|
||||||
|
isDirectory = false;
|
||||||
|
remaining = storage.remaining(index);
|
||||||
|
priority = storage.getPriority(index);
|
||||||
|
} else {
|
||||||
|
isDirectory = file.isDirectory();
|
||||||
|
remaining = -1;
|
||||||
|
priority = -999;
|
||||||
|
}
|
||||||
|
length = isDirectory ? 0 : file.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Negative is reverse
|
||||||
|
*
|
||||||
|
*<ul>
|
||||||
|
*<li>0, 1: Name
|
||||||
|
*<li>5: Size
|
||||||
|
*<li>10: Remaining (needed)
|
||||||
|
*<li>12: File type
|
||||||
|
*<li>13: Priority
|
||||||
|
*</ul>
|
||||||
|
*
|
||||||
|
* @param servlet for file type callback only
|
||||||
|
*/
|
||||||
|
public static Comparator<FileAndIndex> getFileComparator(int type, I2PSnarkServlet servlet) {
|
||||||
|
boolean rev = type < 0;
|
||||||
|
Comparator<FileAndIndex> rv;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
rv = new FileNameComparator();
|
||||||
|
if (rev)
|
||||||
|
rv = Collections.reverseOrder(rv);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -5:
|
||||||
|
case 5:
|
||||||
|
rv = new FAISizeComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -10:
|
||||||
|
case 10:
|
||||||
|
rv = new FAIRemainingComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -12:
|
||||||
|
case 12:
|
||||||
|
rv = new FAITypeComparator(rev, servlet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -13:
|
||||||
|
case 13:
|
||||||
|
rv = new FAIPriorityComparator(rev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort alphabetically in current locale, ignore case,
|
||||||
|
* directories first
|
||||||
|
* @since 0.9.6 moved from I2PSnarkServlet in 0.9.16
|
||||||
|
*/
|
||||||
|
private static class FileNameComparator implements Comparator<FileAndIndex>, Serializable {
|
||||||
|
|
||||||
|
public int compare(FileAndIndex l, FileAndIndex r) {
|
||||||
|
return comp(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int comp(FileAndIndex l, FileAndIndex r) {
|
||||||
|
boolean ld = l.isDirectory;
|
||||||
|
boolean rd = r.isDirectory;
|
||||||
|
if (ld && !rd)
|
||||||
|
return -1;
|
||||||
|
if (rd && !ld)
|
||||||
|
return 1;
|
||||||
|
return Collator.getInstance().compare(l.file.getName(), r.file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward or reverse sort, but the fallback is always forward
|
||||||
|
*/
|
||||||
|
private static abstract class FAISort implements Comparator<FileAndIndex>, Serializable {
|
||||||
|
|
||||||
|
private final boolean _rev;
|
||||||
|
|
||||||
|
public FAISort(boolean rev) {
|
||||||
|
_rev = rev;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(FileAndIndex l, FileAndIndex r) {
|
||||||
|
int rv = compareIt(l, r);
|
||||||
|
if (rv != 0)
|
||||||
|
return _rev ? 0 - rv : rv;
|
||||||
|
return FileNameComparator.comp(l, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int compareIt(FileAndIndex l, FileAndIndex r);
|
||||||
|
|
||||||
|
protected static int compLong(long l, long r) {
|
||||||
|
if (l < r)
|
||||||
|
return -1;
|
||||||
|
if (l > r)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FAIRemainingComparator extends FAISort {
|
||||||
|
|
||||||
|
public FAIRemainingComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(FileAndIndex l, FileAndIndex r) {
|
||||||
|
return compLong(l.remaining, r.remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FAISizeComparator extends FAISort {
|
||||||
|
|
||||||
|
public FAISizeComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
public int compareIt(FileAndIndex l, FileAndIndex r) {
|
||||||
|
return compLong(l.length, r.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FAITypeComparator extends FAISort {
|
||||||
|
|
||||||
|
private final I2PSnarkServlet servlet;
|
||||||
|
|
||||||
|
public FAITypeComparator(boolean rev, I2PSnarkServlet servlet) {
|
||||||
|
super(rev);
|
||||||
|
this.servlet = servlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareIt(FileAndIndex l, FileAndIndex r) {
|
||||||
|
String ls = toName(l);
|
||||||
|
String rs = toName(r);
|
||||||
|
return ls.compareTo(rs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toName(FileAndIndex fai) {
|
||||||
|
if (fai.isDirectory)
|
||||||
|
return "0";
|
||||||
|
// arbitrary sort based on icon name
|
||||||
|
return servlet.toIcon(fai.file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FAIPriorityComparator extends FAISort {
|
||||||
|
|
||||||
|
public FAIPriorityComparator(boolean rev) { super(rev); }
|
||||||
|
|
||||||
|
/** highest first */
|
||||||
|
public int compareIt(FileAndIndex l, FileAndIndex r) {
|
||||||
|
return r.priority - l.priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -8,6 +8,7 @@ epub = application/epub+zip
|
|||||||
flac = audio/flac
|
flac = audio/flac
|
||||||
flv = video/x-flv
|
flv = video/x-flv
|
||||||
iso = application/x-iso9660-image
|
iso = application/x-iso9660-image
|
||||||
|
js = text/javascript
|
||||||
m4a = audio/mp4a-latm
|
m4a = audio/mp4a-latm
|
||||||
m4v = video/x-m4v
|
m4v = video/x-m4v
|
||||||
mkv = video/x-matroska
|
mkv = video/x-matroska
|
||||||
|
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 464 B |
Before Width: | Height: | Size: 733 B After Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 587 B After Width: | Height: | Size: 587 B |
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 673 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 889 B |
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
Before Width: | Height: | Size: 653 B After Width: | Height: | Size: 653 B |
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 578 B |
BIN
apps/i2psnark/resources/icons/itoopie_xxsm.png
Normal file
After Width: | Height: | Size: 661 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
Before Width: | Height: | Size: 853 B After Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 635 B |
Before Width: | Height: | Size: 294 B After Width: | Height: | Size: 294 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
93
apps/i2psnark/resources/js/folder.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
function setupbuttons() {
|
||||||
|
updatesetallbuttons();
|
||||||
|
var form = document.forms[0];
|
||||||
|
form.savepri.disabled = true;
|
||||||
|
form.savepri.className = 'disabled';
|
||||||
|
}
|
||||||
|
|
||||||
|
function priorityclicked() {
|
||||||
|
updatesetallbuttons();
|
||||||
|
var form = document.forms[0];
|
||||||
|
form.savepri.disabled = false;
|
||||||
|
form.savepri.className = 'accept';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatesetallbuttons() {
|
||||||
|
var notNorm = false;
|
||||||
|
var notHigh = false;
|
||||||
|
var notSkip = false;
|
||||||
|
var form = document.forms[0];
|
||||||
|
for(i = 0; i < form.elements.length; i++) {
|
||||||
|
var elem = form.elements[i];
|
||||||
|
if (elem.type == 'radio') {
|
||||||
|
if (!elem.checked) {
|
||||||
|
if (elem.className == 'prinorm')
|
||||||
|
notNorm = true;
|
||||||
|
else if (elem.className == 'prihigh')
|
||||||
|
notHigh = true;
|
||||||
|
else
|
||||||
|
notSkip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (notNorm)
|
||||||
|
document.getElementById('setallnorm').className = 'control';
|
||||||
|
else
|
||||||
|
document.getElementById('setallnorm').className = 'controld';
|
||||||
|
if (notHigh)
|
||||||
|
document.getElementById('setallhigh').className = 'control';
|
||||||
|
else
|
||||||
|
document.getElementById('setallhigh').className = 'controld';
|
||||||
|
if (notSkip)
|
||||||
|
document.getElementById('setallskip').className = 'control';
|
||||||
|
else
|
||||||
|
document.getElementById('setallskip').className = 'controld';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setallnorm() {
|
||||||
|
var form = document.forms[0];
|
||||||
|
for(i = 0; i < form.elements.length; i++) {
|
||||||
|
var elem = form.elements[i];
|
||||||
|
if (elem.type == 'radio') {
|
||||||
|
if (elem.className === 'prinorm')
|
||||||
|
elem.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById('setallnorm').className = 'controld';
|
||||||
|
document.getElementById('setallhigh').className = 'control';
|
||||||
|
document.getElementById('setallskip').className = 'control';
|
||||||
|
form.savepri.disabled = false;
|
||||||
|
form.savepri.className = 'accept';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setallhigh() {
|
||||||
|
var form = document.forms[0];
|
||||||
|
for(i = 0; i < form.elements.length; i++) {
|
||||||
|
var elem = form.elements[i];
|
||||||
|
if (elem.type == 'radio') {
|
||||||
|
if (elem.className === 'prihigh')
|
||||||
|
elem.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById('setallnorm').className = 'control';
|
||||||
|
document.getElementById('setallhigh').className = 'controld';
|
||||||
|
document.getElementById('setallskip').className = 'control';
|
||||||
|
form.savepri.disabled = false;
|
||||||
|
form.savepri.className = 'accept';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setallskip() {
|
||||||
|
var form = document.forms[0];
|
||||||
|
for(i = 0; i < form.elements.length; i++) {
|
||||||
|
var elem = form.elements[i];
|
||||||
|
if (elem.type == 'radio') {
|
||||||
|
if (elem.className === 'priskip')
|
||||||
|
elem.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.getElementById('setallnorm').className = 'control';
|
||||||
|
document.getElementById('setallhigh').className = 'control';
|
||||||
|
document.getElementById('setallskip').className = 'controld';
|
||||||
|
form.savepri.disabled = false;
|
||||||
|
form.savepri.className = 'accept';
|
||||||
|
}
|
@@ -40,6 +40,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -256,7 +257,15 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gui) {
|
if (gui) {
|
||||||
new I2PTunnelGUI(this);
|
// removed from source, now in i2p.scripts
|
||||||
|
//new I2PTunnelGUI(this);
|
||||||
|
try {
|
||||||
|
Class<?> cls = Class.forName("net.i2p.i2ptunnel.I2PTunnelGUI");
|
||||||
|
Constructor<?> con = cls.getConstructor(I2PTunnel.class);
|
||||||
|
con.newInstance(this);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new UnsupportedOperationException("GUI is not available, try -cli", t);
|
||||||
|
}
|
||||||
} else if (cli) {
|
} else if (cli) {
|
||||||
try {
|
try {
|
||||||
System.out.println("Enter 'help' for help.");
|
System.out.println("Enter 'help' for help.");
|
||||||
|
@@ -1,48 +0,0 @@
|
|||||||
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
|
|
||||||
* (c) 2003 - 2004 mihi
|
|
||||||
*/
|
|
||||||
package net.i2p.i2ptunnel;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.Frame;
|
|
||||||
import java.awt.TextArea;
|
|
||||||
import java.awt.TextField;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AWT gui since kaffe doesn't support swing yet
|
|
||||||
*/
|
|
||||||
public class I2PTunnelGUI extends Frame implements ActionListener, Logging {
|
|
||||||
|
|
||||||
TextField input;
|
|
||||||
TextArea log;
|
|
||||||
I2PTunnel t;
|
|
||||||
|
|
||||||
public I2PTunnelGUI(I2PTunnel t) {
|
|
||||||
super("I2PTunnel control panel");
|
|
||||||
this.t = t;
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
add("South", input = new TextField());
|
|
||||||
input.addActionListener(this);
|
|
||||||
Font font = new Font("Monospaced", Font.PLAIN, 12);
|
|
||||||
add("Center", log = new TextArea("", 20, 80, TextArea.SCROLLBARS_VERTICAL_ONLY));
|
|
||||||
log.setFont(font);
|
|
||||||
log.setEditable(false);
|
|
||||||
log("enter 'help' for help.");
|
|
||||||
pack();
|
|
||||||
setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void log(String s) {
|
|
||||||
log.append(s + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent evt) {
|
|
||||||
log("I2PTunnel>" + input.getText());
|
|
||||||
t.runCommand(input.getText(), this);
|
|
||||||
log("---");
|
|
||||||
input.setText("");
|
|
||||||
}
|
|
||||||
}
|
|
@@ -601,9 +601,12 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
|
|||||||
return;
|
return;
|
||||||
int status = ise != null ? ise.getStatus() : -1;
|
int status = ise != null ? ise.getStatus() : -1;
|
||||||
String error;
|
String error;
|
||||||
//TODO MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION
|
|
||||||
if (status == MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET) {
|
if (status == MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET) {
|
||||||
|
// We won't get this one unless it is treated as a hard failure
|
||||||
|
// in streaming. See PacketQueue.java
|
||||||
error = usingWWWProxy ? "nolsp" : "nols";
|
error = usingWWWProxy ? "nolsp" : "nols";
|
||||||
|
} else if (status == MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION) {
|
||||||
|
error = usingWWWProxy ? "encp" : "enc";
|
||||||
} else {
|
} else {
|
||||||
error = usingWWWProxy ? "dnfp" : "dnf";
|
error = usingWWWProxy ? "dnfp" : "dnf";
|
||||||
}
|
}
|
||||||
|
@@ -188,8 +188,7 @@ public class EditBean extends IndexBean {
|
|||||||
|
|
||||||
/** @since 0.9.12 */
|
/** @since 0.9.12 */
|
||||||
public boolean isSigTypeAvailable(int code) {
|
public boolean isSigTypeAvailable(int code) {
|
||||||
SigType type = SigType.getByCode(code);
|
return SigType.isAvailable(code);
|
||||||
return type != null && type.isAvailable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 0.8.9 */
|
/** @since 0.8.9 */
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project basedir="." default="all" name="jetty">
|
<project basedir="." default="all" name="jetty">
|
||||||
|
|
||||||
<property name="jetty.ver" value="8.1.15.v20140411" />
|
<property name="jetty.ver" value="8.1.16.v20140903" />
|
||||||
<property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
|
<property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
|
||||||
<property name="jetty.sha1" value="41ec2b5e5605c038fb28d1f118669f06b4479e71" />
|
<property name="jetty.sha1" value="5440b33a722d82b746b9ce50168bfce3c22af349" />
|
||||||
<property name="jetty.filename" value="${jetty.base}.zip" />
|
<property name="jetty.filename" value="${jetty.base}.zip" />
|
||||||
<property name="jetty.url" value="http://download.eclipse.org/jetty/${jetty.ver}/dist/${jetty.filename}" />
|
<property name="jetty.url" value="http://download.eclipse.org/jetty/${jetty.ver}/dist/${jetty.filename}" />
|
||||||
<property name="verified.filename" value="verified.txt" />
|
<property name="verified.filename" value="verified.txt" />
|
||||||
|
@@ -5,7 +5,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.transport.TransportManager;
|
import net.i2p.router.transport.TransportManager;
|
||||||
|
@@ -29,8 +29,8 @@ import net.i2p.data.Destination;
|
|||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.Lease;
|
import net.i2p.data.Lease;
|
||||||
import net.i2p.data.LeaseSet;
|
import net.i2p.data.LeaseSet;
|
||||||
import net.i2p.data.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.TunnelPoolSettings;
|
import net.i2p.router.TunnelPoolSettings;
|
||||||
import net.i2p.router.util.HashDistance; // debug
|
import net.i2p.router.util.HashDistance; // debug
|
||||||
@@ -199,10 +199,10 @@ public class NetDbRenderer {
|
|||||||
FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade)_context.netDb();
|
FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade)_context.netDb();
|
||||||
buf.append("<p><b>Total Leasesets: ").append(leases.size());
|
buf.append("<p><b>Total Leasesets: ").append(leases.size());
|
||||||
buf.append("</b></p><p><b>Published (RAP) Leasesets: ").append(netdb.getKnownLeaseSets());
|
buf.append("</b></p><p><b>Published (RAP) Leasesets: ").append(netdb.getKnownLeaseSets());
|
||||||
buf.append("</b></p><p><b>Mod Data: \"").append(DataHelper.getUTF8(_context.routingKeyGenerator().getModData()))
|
buf.append("</b></p><p><b>Mod Data: \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData()))
|
||||||
.append("\" Last Changed: ").append(new Date(_context.routingKeyGenerator().getLastChanged()));
|
.append("\" Last Changed: ").append(new Date(_context.routerKeyGenerator().getLastChanged()));
|
||||||
buf.append("</b></p><p><b>Next Mod Data: \"").append(DataHelper.getUTF8(_context.routingKeyGenerator().getNextModData()))
|
buf.append("</b></p><p><b>Next Mod Data: \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData()))
|
||||||
.append("\" Change in: ").append(DataHelper.formatDuration(_context.routingKeyGenerator().getTimeTillMidnight()));
|
.append("\" Change in: ").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight()));
|
||||||
int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size();
|
int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size();
|
||||||
buf.append("</b></p><p><b>Known Floodfills: ").append(ff);
|
buf.append("</b></p><p><b>Known Floodfills: ").append(ff);
|
||||||
buf.append("</b></p><p><b>Currently Floodfill? ");
|
buf.append("</b></p><p><b>Currently Floodfill? ");
|
||||||
@@ -415,7 +415,9 @@ public class NetDbRenderer {
|
|||||||
// shouldnt happen
|
// shouldnt happen
|
||||||
buf.append("<b>" + _("Published") + ":</b> in ").append(DataHelper.formatDuration2(0-age)).append("???<br>\n");
|
buf.append("<b>" + _("Published") + ":</b> in ").append(DataHelper.formatDuration2(0-age)).append("???<br>\n");
|
||||||
}
|
}
|
||||||
buf.append("<b>" + _("Address(es)") + ":</b> ");
|
buf.append("<b>").append(_("Signing Key")).append(":</b> ")
|
||||||
|
.append(info.getIdentity().getSigningPublicKey().getType().toString());
|
||||||
|
buf.append("<br>\n<b>" + _("Address(es)") + ":</b> ");
|
||||||
String country = _context.commSystem().getCountry(info.getIdentity().getHash());
|
String country = _context.commSystem().getCountry(info.getIdentity().getHash());
|
||||||
if(country != null) {
|
if(country != null) {
|
||||||
buf.append("<img height=\"11\" width=\"16\" alt=\"").append(country.toUpperCase(Locale.US)).append('\"');
|
buf.append("<img height=\"11\" width=\"16\" alt=\"").append(country.toUpperCase(Locale.US)).append('\"');
|
||||||
|
@@ -10,7 +10,7 @@ import java.util.TreeSet;
|
|||||||
|
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.peermanager.DBHistory;
|
import net.i2p.router.peermanager.DBHistory;
|
||||||
import net.i2p.router.peermanager.PeerProfile;
|
import net.i2p.router.peermanager.PeerProfile;
|
||||||
|
@@ -3,8 +3,8 @@ package net.i2p.router.web;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.Signature;
|
import net.i2p.data.Signature;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -15,8 +15,8 @@ import net.i2p.data.DataHelper;
|
|||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.LeaseSet;
|
import net.i2p.data.LeaseSet;
|
||||||
import net.i2p.data.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
@@ -11,7 +11,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.TunnelId;
|
import net.i2p.data.TunnelId;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
@@ -44,7 +44,7 @@ class PacketQueue implements SendMessageStatusListener {
|
|||||||
private static final int FINAL_TAGS_TO_SEND = 4;
|
private static final int FINAL_TAGS_TO_SEND = 4;
|
||||||
private static final int FINAL_TAG_THRESHOLD = 2;
|
private static final int FINAL_TAG_THRESHOLD = 2;
|
||||||
private static final long REMOVE_EXPIRED_TIME = 67*1000;
|
private static final long REMOVE_EXPIRED_TIME = 67*1000;
|
||||||
private static final boolean ENABLE_STATUS_LISTEN = false;
|
private static final boolean ENABLE_STATUS_LISTEN = true;
|
||||||
|
|
||||||
public PacketQueue(I2PAppContext context, I2PSession session, ConnectionManager mgr) {
|
public PacketQueue(I2PAppContext context, I2PSession session, ConnectionManager mgr) {
|
||||||
_context = context;
|
_context = context;
|
||||||
@@ -267,6 +267,20 @@ class PacketQueue implements SendMessageStatusListener {
|
|||||||
_messageStatusMap.remove(id);
|
_messageStatusMap.remove(id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
|
||||||
|
// Ideally we would like to make this a hard failure,
|
||||||
|
// but it caused far too many fast-fails that were then
|
||||||
|
// resolved by the user clicking reload in his browser.
|
||||||
|
// Until the LS fetch is faster and more reliable,
|
||||||
|
// or we increase the timeout for it,
|
||||||
|
// we can't treat this one as a hard fail.
|
||||||
|
// Let the streaming retransmission paper over the problem.
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("LS lookup (soft) failure for msg " + msgId + " on " + con);
|
||||||
|
_messageStatusMap.remove(id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL:
|
case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL:
|
||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_ROUTER:
|
case MessageStatusMessage.STATUS_SEND_FAILURE_ROUTER:
|
||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_NETWORK:
|
case MessageStatusMessage.STATUS_SEND_FAILURE_NETWORK:
|
||||||
@@ -280,7 +294,6 @@ class PacketQueue implements SendMessageStatusListener {
|
|||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_DESTINATION:
|
case MessageStatusMessage.STATUS_SEND_FAILURE_DESTINATION:
|
||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET:
|
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET:
|
||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET:
|
case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET:
|
||||||
case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
|
|
||||||
case SendMessageStatusListener.STATUS_CANCELLED:
|
case SendMessageStatusListener.STATUS_CANCELLED:
|
||||||
if (con.getHighestAckedThrough() >= 0) {
|
if (con.getHighestAckedThrough() >= 0) {
|
||||||
// a retxed SYN succeeded before the first SYN failed
|
// a retxed SYN succeeded before the first SYN failed
|
||||||
|
@@ -548,7 +548,7 @@
|
|||||||
windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
|
windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
|
||||||
<group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.oldcrypto:org.bouncycastle.oldcrypto.*:gnu.crypto.*:gnu.getopt:gnu.gettext:com.nettgryppa.security:net.metanotion:net.metanotion.*" />
|
<group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.oldcrypto:org.bouncycastle.oldcrypto.*:gnu.crypto.*:gnu.getopt:gnu.gettext:com.nettgryppa.security:net.metanotion:net.metanotion.*" />
|
||||||
<group title="Streaming Library" packages="net.i2p.client.streaming:net.i2p.client.streaming.impl" />
|
<group title="Streaming Library" packages="net.i2p.client.streaming:net.i2p.client.streaming.impl" />
|
||||||
<group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
|
<group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:net.i2p.data.router:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
|
||||||
<group title="Router Console" packages="net.i2p.router.web:net.i2p.router.update" />
|
<group title="Router Console" packages="net.i2p.router.web:net.i2p.router.update" />
|
||||||
<!-- apps and bridges starting here, alphabetical please -->
|
<!-- apps and bridges starting here, alphabetical please -->
|
||||||
<group title="Addressbook Application" packages="net.i2p.addressbook" />
|
<group title="Addressbook Application" packages="net.i2p.addressbook" />
|
||||||
|
@@ -86,7 +86,6 @@ public class I2PAppContext {
|
|||||||
private SHA256Generator _sha;
|
private SHA256Generator _sha;
|
||||||
protected Clock _clock; // overridden in RouterContext
|
protected Clock _clock; // overridden in RouterContext
|
||||||
private DSAEngine _dsa;
|
private DSAEngine _dsa;
|
||||||
private RoutingKeyGenerator _routingKeyGenerator;
|
|
||||||
private RandomSource _random;
|
private RandomSource _random;
|
||||||
private KeyGenerator _keyGenerator;
|
private KeyGenerator _keyGenerator;
|
||||||
protected KeyRing _keyRing; // overridden in RouterContext
|
protected KeyRing _keyRing; // overridden in RouterContext
|
||||||
@@ -106,7 +105,6 @@ public class I2PAppContext {
|
|||||||
private volatile boolean _shaInitialized;
|
private volatile boolean _shaInitialized;
|
||||||
protected volatile boolean _clockInitialized; // used in RouterContext
|
protected volatile boolean _clockInitialized; // used in RouterContext
|
||||||
private volatile boolean _dsaInitialized;
|
private volatile boolean _dsaInitialized;
|
||||||
private volatile boolean _routingKeyGeneratorInitialized;
|
|
||||||
private volatile boolean _randomInitialized;
|
private volatile boolean _randomInitialized;
|
||||||
private volatile boolean _keyGeneratorInitialized;
|
private volatile boolean _keyGeneratorInitialized;
|
||||||
protected volatile boolean _keyRingInitialized; // used in RouterContext
|
protected volatile boolean _keyRingInitialized; // used in RouterContext
|
||||||
@@ -126,7 +124,7 @@ public class I2PAppContext {
|
|||||||
private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object(), _lock4 = new Object(),
|
private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object(), _lock4 = new Object(),
|
||||||
_lock5 = new Object(), _lock6 = new Object(), _lock7 = new Object(), _lock8 = new Object(),
|
_lock5 = new Object(), _lock6 = new Object(), _lock7 = new Object(), _lock8 = new Object(),
|
||||||
_lock9 = new Object(), _lock10 = new Object(), _lock11 = new Object(), _lock12 = new Object(),
|
_lock9 = new Object(), _lock10 = new Object(), _lock11 = new Object(), _lock12 = new Object(),
|
||||||
_lock13 = new Object(), _lock14 = new Object(), _lock15 = new Object(), _lock16 = new Object(),
|
_lock13 = new Object(), _lock14 = new Object(), _lock16 = new Object(),
|
||||||
_lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object();
|
_lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -851,19 +849,13 @@ public class I2PAppContext {
|
|||||||
* may want to test out how things react when peers don't agree on
|
* may want to test out how things react when peers don't agree on
|
||||||
* how to skew.
|
* how to skew.
|
||||||
*
|
*
|
||||||
|
* As of 0.9.16, returns null in I2PAppContext.
|
||||||
|
* You must be in RouterContext to get a generator.
|
||||||
|
*
|
||||||
|
* @return null always
|
||||||
*/
|
*/
|
||||||
public RoutingKeyGenerator routingKeyGenerator() {
|
public RoutingKeyGenerator routingKeyGenerator() {
|
||||||
if (!_routingKeyGeneratorInitialized)
|
return null;
|
||||||
initializeRoutingKeyGenerator();
|
|
||||||
return _routingKeyGenerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeRoutingKeyGenerator() {
|
|
||||||
synchronized (_lock15) {
|
|
||||||
if (_routingKeyGenerator == null)
|
|
||||||
_routingKeyGenerator = new RoutingKeyGenerator(this);
|
|
||||||
_routingKeyGeneratorInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
135
core/java/src/net/i2p/crypto/ECUtil.java
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
package net.i2p.crypto;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.spec.ECField;
|
||||||
|
import java.security.spec.ECFieldFp;
|
||||||
|
import java.security.spec.ECPoint;
|
||||||
|
import java.security.spec.EllipticCurve;
|
||||||
|
|
||||||
|
import net.i2p.util.NativeBigInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by KeyGenerator.getSigningPublicKey()
|
||||||
|
*
|
||||||
|
* Modified from
|
||||||
|
* http://stackoverflow.com/questions/15727147/scalar-multiplication-of-point-over-elliptic-curve
|
||||||
|
* Apparently public domain.
|
||||||
|
* Supported P-192 only.
|
||||||
|
* Added curve parameters to support all curves.
|
||||||
|
*
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
class ECUtil {
|
||||||
|
|
||||||
|
private static final BigInteger TWO = new BigInteger("2");
|
||||||
|
private static final BigInteger THREE = new BigInteger("3");
|
||||||
|
|
||||||
|
public static ECPoint scalarMult(ECPoint p, BigInteger kin, EllipticCurve curve) {
|
||||||
|
ECPoint r = ECPoint.POINT_INFINITY;
|
||||||
|
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
|
||||||
|
BigInteger k = kin.mod(prime);
|
||||||
|
int length = k.bitLength();
|
||||||
|
byte[] binarray = new byte[length];
|
||||||
|
for (int i = 0; i <= length-1; i++) {
|
||||||
|
binarray[i] = k.mod(TWO).byteValue();
|
||||||
|
k = k.divide(TWO);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = length-1; i >= 0; i--) {
|
||||||
|
// i should start at length-1 not -2 because the MSB of binarry may not be 1
|
||||||
|
r = doublePoint(r, curve);
|
||||||
|
if (binarray[i] == 1)
|
||||||
|
r = addPoint(r, p, curve);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECPoint addPoint(ECPoint r, ECPoint s, EllipticCurve curve) {
|
||||||
|
if (r.equals(s))
|
||||||
|
return doublePoint(r, curve);
|
||||||
|
else if (r.equals(ECPoint.POINT_INFINITY))
|
||||||
|
return s;
|
||||||
|
else if (s.equals(ECPoint.POINT_INFINITY))
|
||||||
|
return r;
|
||||||
|
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
|
||||||
|
BigInteger slope = (r.getAffineY().subtract(s.getAffineY())).multiply(r.getAffineX().subtract(s.getAffineX()).modInverse(prime)).mod(prime);
|
||||||
|
slope = new NativeBigInteger(slope);
|
||||||
|
BigInteger xOut = (slope.modPow(TWO, prime).subtract(r.getAffineX())).subtract(s.getAffineX()).mod(prime);
|
||||||
|
BigInteger yOut = s.getAffineY().negate().mod(prime);
|
||||||
|
yOut = yOut.add(slope.multiply(s.getAffineX().subtract(xOut))).mod(prime);
|
||||||
|
ECPoint out = new ECPoint(xOut, yOut);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECPoint doublePoint(ECPoint r, EllipticCurve curve) {
|
||||||
|
if (r.equals(ECPoint.POINT_INFINITY))
|
||||||
|
return r;
|
||||||
|
BigInteger slope = (r.getAffineX().pow(2)).multiply(THREE);
|
||||||
|
slope = slope.add(curve.getA());
|
||||||
|
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
|
||||||
|
slope = slope.multiply((r.getAffineY().multiply(TWO)).modInverse(prime));
|
||||||
|
BigInteger xOut = slope.pow(2).subtract(r.getAffineX().multiply(TWO)).mod(prime);
|
||||||
|
BigInteger yOut = (r.getAffineY().negate()).add(slope.multiply(r.getAffineX().subtract(xOut))).mod(prime);
|
||||||
|
ECPoint out = new ECPoint(xOut, yOut);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* P-192 test only.
|
||||||
|
* See KeyGenerator.main() for a test of all supported curves.
|
||||||
|
*/
|
||||||
|
/****
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EllipticCurve P192 = ECConstants.P192_SPEC.getCurve();
|
||||||
|
BigInteger xs = new BigInteger("d458e7d127ae671b0c330266d246769353a012073e97acf8", 16);
|
||||||
|
BigInteger ys = new BigInteger("325930500d851f336bddc050cf7fb11b5673a1645086df3b", 16);
|
||||||
|
BigInteger xt = new BigInteger("f22c4395213e9ebe67ddecdd87fdbd01be16fb059b9753a4", 16);
|
||||||
|
BigInteger yt = new BigInteger("264424096af2b3597796db48f8dfb41fa9cecc97691a9c79", 16);
|
||||||
|
ECPoint S = new ECPoint(xs,ys);
|
||||||
|
ECPoint T = new ECPoint(xt,yt);
|
||||||
|
|
||||||
|
// Verifying addition
|
||||||
|
ECPoint Rst = addPoint(S, T, P192);
|
||||||
|
BigInteger xst = new BigInteger("48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290", 16); // Specified value of x of point R for addition in NIST Routine example
|
||||||
|
System.out.println("x-coordinate of point Rst is : " + Rst.getAffineX());
|
||||||
|
System.out.println("y-coordinate of point Rst is : " + Rst.getAffineY());
|
||||||
|
if (Rst.getAffineX().equals(xst))
|
||||||
|
System.out.println("Adding is correct");
|
||||||
|
else
|
||||||
|
System.out.println("Adding FAIL");
|
||||||
|
|
||||||
|
//Verifying Doubling
|
||||||
|
BigInteger xr = new BigInteger("30c5bc6b8c7da25354b373dc14dd8a0eba42d25a3f6e6962", 16); // Specified value of x of point R for doubling in NIST Routine example
|
||||||
|
BigInteger yr = new BigInteger("0dde14bc4249a721c407aedbf011e2ddbbcb2968c9d889cf", 16);
|
||||||
|
ECPoint R2s = new ECPoint(xr, yr); // Specified value of y of point R for doubling in NIST Routine example
|
||||||
|
System.out.println("x-coordinate of point R2s is : " + R2s.getAffineX());
|
||||||
|
System.out.println("y-coordinate of point R2s is : " + R2s.getAffineY());
|
||||||
|
System.out.println("x-coordinate of calculated point is : " + doublePoint(S, P192).getAffineX());
|
||||||
|
System.out.println("y-coordinate of calculated point is : " + doublePoint(S, P192).getAffineY());
|
||||||
|
if (R2s.getAffineX().equals(doublePoint(S, P192).getAffineX()) &&
|
||||||
|
R2s.getAffineY().equals(doublePoint(S, P192).getAffineY()))
|
||||||
|
System.out.println("Doubling is correct");
|
||||||
|
else
|
||||||
|
System.out.println("Doubling FAIL");
|
||||||
|
|
||||||
|
xr = new BigInteger("1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31", 16); // Specified value of x of point R for scalar Multiplication in NIST Routine example
|
||||||
|
yr = new BigInteger("5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06", 16); // Specified value of y of point R for scalar Multiplication in NIST Routine example
|
||||||
|
ECPoint Rds = new ECPoint(xr, yr);
|
||||||
|
BigInteger d = new BigInteger("a78a236d60baec0c5dd41b33a542463a8255391af64c74ee", 16);
|
||||||
|
|
||||||
|
ECPoint Rs = scalarMult(S, d, P192);
|
||||||
|
|
||||||
|
System.out.println("x-coordinate of point Rds is : " + Rds.getAffineX());
|
||||||
|
System.out.println("y-coordinate of point Rds is : " + Rds.getAffineY());
|
||||||
|
System.out.println("x-coordinate of calculated point is : " + Rs.getAffineX());
|
||||||
|
System.out.println("y-coordinate of calculated point is : " + Rs.getAffineY());
|
||||||
|
|
||||||
|
|
||||||
|
if (Rds.getAffineX().equals(Rs.getAffineX()) &&
|
||||||
|
Rds.getAffineY().equals(Rs.getAffineY()))
|
||||||
|
System.out.println("Scalar Multiplication is correct");
|
||||||
|
else
|
||||||
|
System.out.println("Scalar Multiplication FAIL");
|
||||||
|
}
|
||||||
|
****/
|
||||||
|
}
|
@@ -56,6 +56,9 @@ public class ElGamalEngine {
|
|||||||
private final Log _log;
|
private final Log _log;
|
||||||
private final I2PAppContext _context;
|
private final I2PAppContext _context;
|
||||||
private final YKGenerator _ykgen;
|
private final YKGenerator _ykgen;
|
||||||
|
|
||||||
|
private static final BigInteger ELGPM1 = CryptoConstants.elgp.subtract(BigInteger.ONE);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ElGamal engine should only be constructed and accessed through the
|
* The ElGamal engine should only be constructed and accessed through the
|
||||||
@@ -171,10 +174,11 @@ public class ElGamalEngine {
|
|||||||
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to encrypt ElGamal block (" + diff + "ms)");
|
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to encrypt ElGamal block (" + diff + "ms)");
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.statManager().addRateData("crypto.elGamal.encrypt", diff, 0);
|
_context.statManager().addRateData("crypto.elGamal.encrypt", diff);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Decrypt the data
|
/** Decrypt the data
|
||||||
* @param encrypted encrypted data, must be exactly 514 bytes
|
* @param encrypted encrypted data, must be exactly 514 bytes
|
||||||
* Contains the two-part encrypted data starting at bytes 0 and 257.
|
* Contains the two-part encrypted data starting at bytes 0 and 257.
|
||||||
@@ -184,26 +188,26 @@ public class ElGamalEngine {
|
|||||||
* @return unencrypted data or null on failure
|
* @return unencrypted data or null on failure
|
||||||
*/
|
*/
|
||||||
public byte[] decrypt(byte encrypted[], PrivateKey privateKey) {
|
public byte[] decrypt(byte encrypted[], PrivateKey privateKey) {
|
||||||
// actually it must be exactly 514 bytes or the arraycopy below will AIOOBE
|
if ((encrypted == null) || (encrypted.length != 514))
|
||||||
if ((encrypted == null) || (encrypted.length > 514))
|
throw new IllegalArgumentException("Data to decrypt must be exactly 514 bytes");
|
||||||
throw new IllegalArgumentException("Data to decrypt must be <= 514 bytes at the moment");
|
|
||||||
long start = _context.clock().now();
|
long start = _context.clock().now();
|
||||||
|
|
||||||
byte[] ybytes = new byte[257];
|
|
||||||
byte[] dbytes = new byte[257];
|
|
||||||
System.arraycopy(encrypted, 0, ybytes, 0, 257);
|
|
||||||
System.arraycopy(encrypted, 257, dbytes, 0, 257);
|
|
||||||
BigInteger y = new NativeBigInteger(1, ybytes);
|
|
||||||
BigInteger d = new NativeBigInteger(1, dbytes);
|
|
||||||
BigInteger a = new NativeBigInteger(1, privateKey.getData());
|
BigInteger a = new NativeBigInteger(1, privateKey.getData());
|
||||||
BigInteger y1p = CryptoConstants.elgp.subtract(BigInteger.ONE).subtract(a);
|
BigInteger y1p = ELGPM1.subtract(a);
|
||||||
|
// we use this buf first for Y, then for D, then for the hash
|
||||||
|
byte[] buf = SimpleByteCache.acquire(257);
|
||||||
|
System.arraycopy(encrypted, 0, buf, 0, 257);
|
||||||
|
BigInteger y = new NativeBigInteger(1, buf);
|
||||||
BigInteger ya = y.modPow(y1p, CryptoConstants.elgp);
|
BigInteger ya = y.modPow(y1p, CryptoConstants.elgp);
|
||||||
|
System.arraycopy(encrypted, 257, buf, 0, 257);
|
||||||
|
BigInteger d = new NativeBigInteger(1, buf);
|
||||||
BigInteger m = ya.multiply(d);
|
BigInteger m = ya.multiply(d);
|
||||||
m = m.mod(CryptoConstants.elgp);
|
m = m.mod(CryptoConstants.elgp);
|
||||||
byte val[] = m.toByteArray();
|
byte val[] = m.toByteArray();
|
||||||
int i = 0;
|
int i;
|
||||||
for (i = 0; i < val.length; i++)
|
for (i = 0; i < val.length; i++) {
|
||||||
if (val[i] != (byte) 0x00) break;
|
if (val[i] != (byte) 0x00) break;
|
||||||
|
}
|
||||||
|
|
||||||
int payloadLen = val.length - i - 1 - Hash.HASH_LENGTH;
|
int payloadLen = val.length - i - 1 - Hash.HASH_LENGTH;
|
||||||
if (payloadLen < 0) {
|
if (payloadLen < 0) {
|
||||||
@@ -220,10 +224,10 @@ public class ElGamalEngine {
|
|||||||
byte rv[] = new byte[payloadLen];
|
byte rv[] = new byte[payloadLen];
|
||||||
System.arraycopy(val, i + 1 + Hash.HASH_LENGTH, rv, 0, rv.length);
|
System.arraycopy(val, i + 1 + Hash.HASH_LENGTH, rv, 0, rv.length);
|
||||||
|
|
||||||
byte[] calcHash = SimpleByteCache.acquire(Hash.HASH_LENGTH);
|
// we reuse buf here for the calculated hash
|
||||||
_context.sha().calculateHash(rv, 0, payloadLen, calcHash, 0);
|
_context.sha().calculateHash(rv, 0, payloadLen, buf, 0);
|
||||||
boolean ok = DataHelper.eq(calcHash, 0, val, i + 1, Hash.HASH_LENGTH);
|
boolean ok = DataHelper.eq(buf, 0, val, i + 1, Hash.HASH_LENGTH);
|
||||||
SimpleByteCache.release(calcHash);
|
SimpleByteCache.release(buf);
|
||||||
|
|
||||||
long end = _context.clock().now();
|
long end = _context.clock().now();
|
||||||
|
|
||||||
@@ -233,7 +237,7 @@ public class ElGamalEngine {
|
|||||||
_log.warn("Took too long to decrypt and verify ElGamal block (" + diff + "ms)");
|
_log.warn("Took too long to decrypt and verify ElGamal block (" + diff + "ms)");
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.statManager().addRateData("crypto.elGamal.decrypt", diff, 0);
|
_context.statManager().addRateData("crypto.elGamal.decrypt", diff);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
//_log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length));
|
//_log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length));
|
||||||
|
@@ -12,11 +12,25 @@ package net.i2p.crypto;
|
|||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.ProviderException;
|
import java.security.ProviderException;
|
||||||
|
import java.security.interfaces.ECPrivateKey;
|
||||||
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.security.spec.ECParameterSpec;
|
||||||
|
import java.security.spec.ECPoint;
|
||||||
|
import java.security.spec.ECPublicKeySpec;
|
||||||
|
import java.security.spec.EllipticCurve;
|
||||||
|
import java.security.spec.RSAKeyGenParameterSpec;
|
||||||
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||||
|
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.PrivateKey;
|
import net.i2p.data.PrivateKey;
|
||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
@@ -268,24 +282,56 @@ public class KeyGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Convert a SigningPrivateKey to a SigningPublicKey.
|
/** Convert a SigningPrivateKey to a SigningPublicKey.
|
||||||
* DSA-SHA1 only.
|
* As of 0.9.16, supports all key types.
|
||||||
*
|
*
|
||||||
* @param priv a SigningPrivateKey object
|
* @param priv a SigningPrivateKey object
|
||||||
* @return a SigningPublicKey object
|
* @return a SigningPublicKey object
|
||||||
* @throws IllegalArgumentException on bad key
|
* @throws IllegalArgumentException on bad key or unknown type
|
||||||
*/
|
*/
|
||||||
public static SigningPublicKey getSigningPublicKey(SigningPrivateKey priv) {
|
public static SigningPublicKey getSigningPublicKey(SigningPrivateKey priv) {
|
||||||
if (priv.getType() != SigType.DSA_SHA1)
|
SigType type = priv.getType();
|
||||||
throw new IllegalArgumentException();
|
if (type == null)
|
||||||
BigInteger x = new NativeBigInteger(1, priv.toByteArray());
|
throw new IllegalArgumentException("Unknown type");
|
||||||
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
|
|
||||||
SigningPublicKey pub = new SigningPublicKey();
|
|
||||||
try {
|
try {
|
||||||
pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
|
switch (type.getBaseAlgorithm()) {
|
||||||
} catch (InvalidKeyException ike) {
|
case DSA:
|
||||||
throw new IllegalArgumentException(ike);
|
BigInteger x = new NativeBigInteger(1, priv.toByteArray());
|
||||||
|
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
|
||||||
|
SigningPublicKey pub = new SigningPublicKey();
|
||||||
|
pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
|
||||||
|
return pub;
|
||||||
|
|
||||||
|
case EC:
|
||||||
|
ECPrivateKey ecpriv = SigUtil.toJavaECKey(priv);
|
||||||
|
BigInteger s = ecpriv.getS();
|
||||||
|
ECParameterSpec spec = (ECParameterSpec) type.getParams();
|
||||||
|
EllipticCurve curve = spec.getCurve();
|
||||||
|
ECPoint g = spec.getGenerator();
|
||||||
|
ECPoint w = ECUtil.scalarMult(g, s, curve);
|
||||||
|
ECPublicKeySpec ecks = new ECPublicKeySpec(w, ecpriv.getParams());
|
||||||
|
KeyFactory eckf = KeyFactory.getInstance("EC");
|
||||||
|
ECPublicKey ecpub = (ECPublicKey) eckf.generatePublic(ecks);
|
||||||
|
return SigUtil.fromJavaKey(ecpub, type);
|
||||||
|
|
||||||
|
case RSA:
|
||||||
|
RSAPrivateKey rsapriv = SigUtil.toJavaRSAKey(priv);
|
||||||
|
BigInteger exp = ((RSAKeyGenParameterSpec)type.getParams()).getPublicExponent();
|
||||||
|
RSAPublicKeySpec rsaks = new RSAPublicKeySpec(rsapriv.getModulus(), exp);
|
||||||
|
KeyFactory rsakf = KeyFactory.getInstance("RSA");
|
||||||
|
RSAPublicKey rsapub = (RSAPublicKey) rsakf.generatePublic(rsaks);
|
||||||
|
return SigUtil.fromJavaKey(rsapub, type);
|
||||||
|
|
||||||
|
case EdDSA:
|
||||||
|
EdDSAPrivateKey epriv = SigUtil.toJavaEdDSAKey(priv);
|
||||||
|
EdDSAPublicKey epub = new EdDSAPublicKey(new EdDSAPublicKeySpec(epriv.getA(), epriv.getParams()));
|
||||||
|
return SigUtil.fromJavaKey(epub, type);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported algorithm");
|
||||||
|
}
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
throw new IllegalArgumentException("Conversion failed", gse);
|
||||||
}
|
}
|
||||||
return pub;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
@@ -322,14 +368,20 @@ public class KeyGenerator {
|
|||||||
long stime = 0;
|
long stime = 0;
|
||||||
long vtime = 0;
|
long vtime = 0;
|
||||||
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
|
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
|
||||||
//System.out.println("pubkey " + keys[0]);
|
SigningPublicKey pubkey = (SigningPublicKey) keys[0];
|
||||||
|
SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
|
||||||
|
SigningPublicKey pubkey2 = getSigningPublicKey(privkey);
|
||||||
|
if (pubkey.equals(pubkey2))
|
||||||
|
System.out.println(type + " private-to-public test PASSED");
|
||||||
|
else
|
||||||
|
System.out.println(type + " private-to-public test FAILED");
|
||||||
//System.out.println("privkey " + keys[1]);
|
//System.out.println("privkey " + keys[1]);
|
||||||
for (int i = 0; i < runs; i++) {
|
for (int i = 0; i < runs; i++) {
|
||||||
RandomSource.getInstance().nextBytes(src);
|
RandomSource.getInstance().nextBytes(src);
|
||||||
long start = System.nanoTime();
|
long start = System.nanoTime();
|
||||||
Signature sig = DSAEngine.getInstance().sign(src, (SigningPrivateKey) keys[1]);
|
Signature sig = DSAEngine.getInstance().sign(src, privkey);
|
||||||
long mid = System.nanoTime();
|
long mid = System.nanoTime();
|
||||||
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, (SigningPublicKey) keys[0]);
|
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, pubkey);
|
||||||
long end = System.nanoTime();
|
long end = System.nanoTime();
|
||||||
stime += mid - start;
|
stime += mid - start;
|
||||||
vtime += end - mid;
|
vtime += end - mid;
|
||||||
|
@@ -345,7 +345,7 @@ public class SigUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated unused
|
*
|
||||||
*/
|
*/
|
||||||
public static RSAPrivateKey toJavaRSAKey(SigningPrivateKey pk)
|
public static RSAPrivateKey toJavaRSAKey(SigningPrivateKey pk)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
@@ -358,7 +358,7 @@ public class SigUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated unused
|
*
|
||||||
*/
|
*/
|
||||||
public static SigningPublicKey fromJavaKey(RSAPublicKey pk, SigType type)
|
public static SigningPublicKey fromJavaKey(RSAPublicKey pk, SigType type)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
|
@@ -24,20 +24,15 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@@ -638,13 +633,17 @@ public class DataHelper {
|
|||||||
* Integers are a fixed number of bytes (numBytes), stored as unsigned integers in network byte order.
|
* Integers are a fixed number of bytes (numBytes), stored as unsigned integers in network byte order.
|
||||||
* @param value value to write out, non-negative
|
* @param value value to write out, non-negative
|
||||||
* @param rawStream stream to write to
|
* @param rawStream stream to write to
|
||||||
* @param numBytes number of bytes to write the number into (padding as necessary)
|
* @param numBytes number of bytes to write the number into, 1-8 (padding as necessary)
|
||||||
* @throws DataFormatException if value is negative
|
* @throws DataFormatException if value is negative or if numBytes not 1-8
|
||||||
* @throws IOException if there is an IO error writing to the stream
|
* @throws IOException if there is an IO error writing to the stream
|
||||||
*/
|
*/
|
||||||
public static void writeLong(OutputStream rawStream, int numBytes, long value)
|
public static void writeLong(OutputStream rawStream, int numBytes, long value)
|
||||||
throws DataFormatException, IOException {
|
throws DataFormatException, IOException {
|
||||||
if (value < 0) throw new DataFormatException("Value is negative (" + value + ")");
|
if (numBytes <= 0 || numBytes > 8)
|
||||||
|
// probably got the args backwards
|
||||||
|
throw new DataFormatException("Bad byte count " + numBytes);
|
||||||
|
if (value < 0)
|
||||||
|
throw new DataFormatException("Value is negative (" + value + ")");
|
||||||
for (int i = (numBytes - 1) * 8; i >= 0; i -= 8) {
|
for (int i = (numBytes - 1) * 8; i >= 0; i -= 8) {
|
||||||
byte cur = (byte) (value >> i);
|
byte cur = (byte) (value >> i);
|
||||||
rawStream.write(cur);
|
rawStream.write(cur);
|
||||||
@@ -667,7 +666,7 @@ public class DataHelper {
|
|||||||
* @param value non-negative
|
* @param value non-negative
|
||||||
*/
|
*/
|
||||||
public static void toLong(byte target[], int offset, int numBytes, long value) throws IllegalArgumentException {
|
public static void toLong(byte target[], int offset, int numBytes, long value) throws IllegalArgumentException {
|
||||||
if (numBytes <= 0) throw new IllegalArgumentException("Invalid number of bytes");
|
if (numBytes <= 0 || numBytes > 8) throw new IllegalArgumentException("Invalid number of bytes");
|
||||||
if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
|
if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
|
||||||
|
|
||||||
for (int i = offset + numBytes - 1; i >= offset; i--) {
|
for (int i = offset + numBytes - 1; i >= offset; i--) {
|
||||||
@@ -1425,58 +1424,6 @@ public class DataHelper {
|
|||||||
out.write(data);
|
out.write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort based on the Hash of the DataStructure.
|
|
||||||
* Warning - relatively slow.
|
|
||||||
* WARNING - this sort order must be consistent network-wide, so while the order is arbitrary,
|
|
||||||
* it cannot be changed.
|
|
||||||
* Why? Just because it has to be consistent so signing will work.
|
|
||||||
* How to spec as returning the same type as the param?
|
|
||||||
* DEPRECATED - Only used by RouterInfo.
|
|
||||||
*
|
|
||||||
* @return a new list
|
|
||||||
*/
|
|
||||||
public static List<? extends DataStructure> sortStructures(Collection<? extends DataStructure> dataStructures) {
|
|
||||||
if (dataStructures == null) return Collections.emptyList();
|
|
||||||
|
|
||||||
// This used to use Hash.toString(), which is insane, since a change to toString()
|
|
||||||
// would break the whole network. Now use Hash.toBase64().
|
|
||||||
// Note that the Base64 sort order is NOT the same as the raw byte sort order,
|
|
||||||
// despite what you may read elsewhere.
|
|
||||||
|
|
||||||
//ArrayList<DataStructure> rv = new ArrayList(dataStructures.size());
|
|
||||||
//TreeMap<String, DataStructure> tm = new TreeMap();
|
|
||||||
//for (DataStructure struct : dataStructures) {
|
|
||||||
// tm.put(struct.calculateHash().toString(), struct);
|
|
||||||
//}
|
|
||||||
//for (DataStructure struct : tm.values()) {
|
|
||||||
// rv.add(struct);
|
|
||||||
//}
|
|
||||||
ArrayList<DataStructure> rv = new ArrayList<DataStructure>(dataStructures);
|
|
||||||
sortStructureList(rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See above.
|
|
||||||
* DEPRECATED - Only used by RouterInfo.
|
|
||||||
*
|
|
||||||
* @since 0.9
|
|
||||||
*/
|
|
||||||
static void sortStructureList(List<? extends DataStructure> dataStructures) {
|
|
||||||
Collections.sort(dataStructures, new DataStructureComparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See sortStructures() comments.
|
|
||||||
* @since 0.8.3
|
|
||||||
*/
|
|
||||||
private static class DataStructureComparator implements Comparator<DataStructure>, Serializable {
|
|
||||||
public int compare(DataStructure l, DataStructure r) {
|
|
||||||
return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: formatDuration2() recommended in most cases for readability
|
* NOTE: formatDuration2() recommended in most cases for readability
|
||||||
*/
|
*/
|
||||||
|
@@ -11,6 +11,7 @@ package net.i2p.data;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.crypto.DSAEngine;
|
import net.i2p.crypto.DSAEngine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,7 +48,7 @@ public abstract class DatabaseEntry extends DataStructureImpl {
|
|||||||
|
|
||||||
protected volatile Signature _signature;
|
protected volatile Signature _signature;
|
||||||
protected volatile Hash _currentRoutingKey;
|
protected volatile Hash _currentRoutingKey;
|
||||||
protected volatile byte[] _routingKeyGenMod;
|
protected volatile long _routingKeyGenMod;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A common interface to the timestamp of the two subclasses.
|
* A common interface to the timestamp of the two subclasses.
|
||||||
@@ -106,11 +107,15 @@ public abstract class DatabaseEntry extends DataStructureImpl {
|
|||||||
* Get the routing key for the structure using the current modifier in the RoutingKeyGenerator.
|
* Get the routing key for the structure using the current modifier in the RoutingKeyGenerator.
|
||||||
* This only calculates a new one when necessary though (if the generator's key modifier changes)
|
* This only calculates a new one when necessary though (if the generator's key modifier changes)
|
||||||
*
|
*
|
||||||
|
* @throws IllegalStateException if not in RouterContext
|
||||||
*/
|
*/
|
||||||
public Hash getRoutingKey() {
|
public Hash getRoutingKey() {
|
||||||
RoutingKeyGenerator gen = RoutingKeyGenerator.getInstance();
|
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||||
byte[] mod = gen.getModData();
|
if (!ctx.isRouterContext())
|
||||||
if (!Arrays.equals(mod, _routingKeyGenMod)) {
|
throw new IllegalStateException("Not in router context");
|
||||||
|
RoutingKeyGenerator gen = ctx.routingKeyGenerator();
|
||||||
|
long mod = gen.getLastChanged();
|
||||||
|
if (mod != _routingKeyGenMod) {
|
||||||
_currentRoutingKey = gen.getRoutingKey(getHash());
|
_currentRoutingKey = gen.getRoutingKey(getHash());
|
||||||
_routingKeyGenMod = mod;
|
_routingKeyGenMod = mod;
|
||||||
}
|
}
|
||||||
@@ -124,9 +129,16 @@ public abstract class DatabaseEntry extends DataStructureImpl {
|
|||||||
_currentRoutingKey = key;
|
_currentRoutingKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if not in RouterContext
|
||||||
|
*/
|
||||||
public boolean validateRoutingKey() {
|
public boolean validateRoutingKey() {
|
||||||
|
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||||
|
if (!ctx.isRouterContext())
|
||||||
|
throw new IllegalStateException("Not in router context");
|
||||||
|
RoutingKeyGenerator gen = ctx.routingKeyGenerator();
|
||||||
Hash destKey = getHash();
|
Hash destKey = getHash();
|
||||||
Hash rk = RoutingKeyGenerator.getInstance().getRoutingKey(destKey);
|
Hash rk = gen.getRoutingKey(destKey);
|
||||||
return rk.equals(getRoutingKey());
|
return rk.equals(getRoutingKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -77,6 +77,13 @@ public class KeysAndCert extends DataStructureImpl {
|
|||||||
_signingKey = key;
|
_signingKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public byte[] getPadding() {
|
||||||
|
return _padding;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws IllegalStateException if was already set
|
* @throws IllegalStateException if was already set
|
||||||
* @since 0.9.12
|
* @since 0.9.12
|
||||||
@@ -114,6 +121,8 @@ public class KeysAndCert extends DataStructureImpl {
|
|||||||
_publicKey.writeBytes(out);
|
_publicKey.writeBytes(out);
|
||||||
if (_padding != null)
|
if (_padding != null)
|
||||||
out.write(_padding);
|
out.write(_padding);
|
||||||
|
else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES)
|
||||||
|
throw new DataFormatException("No padding set");
|
||||||
_signingKey.writeTruncatedBytes(out);
|
_signingKey.writeTruncatedBytes(out);
|
||||||
_certificate.writeBytes(out);
|
_certificate.writeBytes(out);
|
||||||
}
|
}
|
||||||
|
@@ -50,6 +50,7 @@ public class PrivateKey extends SimpleDataStructure {
|
|||||||
/** derives a new PublicKey object derived from the secret contents
|
/** derives a new PublicKey object derived from the secret contents
|
||||||
* of this PrivateKey
|
* of this PrivateKey
|
||||||
* @return a PublicKey object
|
* @return a PublicKey object
|
||||||
|
* @throws IllegalArgumentException on bad key
|
||||||
*/
|
*/
|
||||||
public PublicKey toPublic() {
|
public PublicKey toPublic() {
|
||||||
return KeyGenerator.getPublicKey(this);
|
return KeyGenerator.getPublicKey(this);
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
package net.i2p.data;
|
package net.i2p.data;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -24,6 +26,7 @@ import net.i2p.crypto.DSAEngine;
|
|||||||
import net.i2p.crypto.KeyGenerator;
|
import net.i2p.crypto.KeyGenerator;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.util.RandomSource;
|
import net.i2p.util.RandomSource;
|
||||||
|
import net.i2p.util.SecureFileOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This helper class reads and writes files in the
|
* This helper class reads and writes files in the
|
||||||
@@ -48,11 +51,11 @@ public class PrivateKeyFile {
|
|||||||
|
|
||||||
private static final int HASH_EFFORT = VerifiedDestination.MIN_HASHCASH_EFFORT;
|
private static final int HASH_EFFORT = VerifiedDestination.MIN_HASHCASH_EFFORT;
|
||||||
|
|
||||||
private final File file;
|
protected final File file;
|
||||||
private final I2PClient client;
|
private final I2PClient client;
|
||||||
private Destination dest;
|
protected Destination dest;
|
||||||
private PrivateKey privKey;
|
protected PrivateKey privKey;
|
||||||
private SigningPrivateKey signingPrivKey;
|
protected SigningPrivateKey signingPrivKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new PrivateKeyFile, or modify an existing one, with various
|
* Create a new PrivateKeyFile, or modify an existing one, with various
|
||||||
@@ -224,6 +227,16 @@ public class PrivateKeyFile {
|
|||||||
*/
|
*/
|
||||||
public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert,
|
public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert,
|
||||||
PrivateKey pk, SigningPrivateKey spk) {
|
PrivateKey pk, SigningPrivateKey spk) {
|
||||||
|
this(file, pubkey, spubkey, cert, pk, spk, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param padding null OK, must be non-null if spubkey length < 128
|
||||||
|
* @throws IllegalArgumentException on mismatch of spubkey and spk types
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert,
|
||||||
|
PrivateKey pk, SigningPrivateKey spk, byte[] padding) {
|
||||||
if (spubkey.getType() != spk.getType())
|
if (spubkey.getType() != spk.getType())
|
||||||
throw new IllegalArgumentException("Signing key type mismatch");
|
throw new IllegalArgumentException("Signing key type mismatch");
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@@ -232,6 +245,8 @@ public class PrivateKeyFile {
|
|||||||
this.dest.setPublicKey(pubkey);
|
this.dest.setPublicKey(pubkey);
|
||||||
this.dest.setSigningPublicKey(spubkey);
|
this.dest.setSigningPublicKey(spubkey);
|
||||||
this.dest.setCertificate(cert);
|
this.dest.setCertificate(cert);
|
||||||
|
if (padding != null)
|
||||||
|
this.dest.setPadding(padding);
|
||||||
this.privKey = pk;
|
this.privKey = pk;
|
||||||
this.signingPrivKey = spk;
|
this.signingPrivKey = spk;
|
||||||
}
|
}
|
||||||
@@ -241,9 +256,9 @@ public class PrivateKeyFile {
|
|||||||
*/
|
*/
|
||||||
public Destination createIfAbsent() throws I2PException, IOException, DataFormatException {
|
public Destination createIfAbsent() throws I2PException, IOException, DataFormatException {
|
||||||
if(!this.file.exists()) {
|
if(!this.file.exists()) {
|
||||||
FileOutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
out = new FileOutputStream(this.file);
|
out = new SecureFileOutputStream(this.file);
|
||||||
if (this.client != null)
|
if (this.client != null)
|
||||||
this.client.createDestination(out);
|
this.client.createDestination(out);
|
||||||
else
|
else
|
||||||
@@ -257,7 +272,10 @@ public class PrivateKeyFile {
|
|||||||
return getDestination();
|
return getDestination();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Also sets the local privKey and signingPrivKey */
|
/**
|
||||||
|
* If the destination is not set, read it in from the file.
|
||||||
|
* Also sets the local privKey and signingPrivKey.
|
||||||
|
*/
|
||||||
public Destination getDestination() throws I2PSessionException, IOException, DataFormatException {
|
public Destination getDestination() throws I2PSessionException, IOException, DataFormatException {
|
||||||
if (dest == null) {
|
if (dest == null) {
|
||||||
I2PSession s = open();
|
I2PSession s = open();
|
||||||
@@ -408,9 +426,9 @@ public class PrivateKeyFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public I2PSession open(Properties opts) throws I2PSessionException, IOException {
|
public I2PSession open(Properties opts) throws I2PSessionException, IOException {
|
||||||
FileInputStream in = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
in = new FileInputStream(this.file);
|
in = new BufferedInputStream(new FileInputStream(this.file));
|
||||||
I2PSession s = this.client.createSession(in, opts);
|
I2PSession s = this.client.createSession(in, opts);
|
||||||
return s;
|
return s;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -424,13 +442,12 @@ public class PrivateKeyFile {
|
|||||||
* Copied from I2PClientImpl.createDestination()
|
* Copied from I2PClientImpl.createDestination()
|
||||||
*/
|
*/
|
||||||
public void write() throws IOException, DataFormatException {
|
public void write() throws IOException, DataFormatException {
|
||||||
FileOutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
out = new FileOutputStream(this.file);
|
out = new SecureFileOutputStream(this.file);
|
||||||
this.dest.writeBytes(out);
|
this.dest.writeBytes(out);
|
||||||
this.privKey.writeBytes(out);
|
this.privKey.writeBytes(out);
|
||||||
this.signingPrivKey.writeBytes(out);
|
this.signingPrivKey.writeBytes(out);
|
||||||
out.flush();
|
|
||||||
} finally {
|
} finally {
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
try { out.close(); } catch (IOException ioe) {}
|
try { out.close(); } catch (IOException ioe) {}
|
||||||
@@ -438,6 +455,23 @@ public class PrivateKeyFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that the PublicKey matches the PrivateKey, and
|
||||||
|
* the SigningPublicKey matches the SigningPrivateKey.
|
||||||
|
*
|
||||||
|
* @return success
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public boolean validateKeyPairs() {
|
||||||
|
try {
|
||||||
|
if (!dest.getPublicKey().equals(KeyGenerator.getPublicKey(privKey)))
|
||||||
|
return false;
|
||||||
|
return dest.getSigningPublicKey().equals(KeyGenerator.getSigningPublicKey(signingPrivKey));
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder s = new StringBuilder(128);
|
StringBuilder s = new StringBuilder(128);
|
||||||
|
@@ -9,215 +9,40 @@ package net.i2p.data;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.crypto.SHA256Generator;
|
|
||||||
import net.i2p.util.HexDump;
|
|
||||||
import net.i2p.util.Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to manage the munging of hashes into routing keys - given a hash,
|
* Component to manage the munging of hashes into routing keys - given a hash,
|
||||||
* perform some consistent transformation against it and return the result.
|
* perform some consistent transformation against it and return the result.
|
||||||
* This transformation is fed by the current "mod data".
|
* This transformation is fed by the current "mod data".
|
||||||
*
|
*
|
||||||
* Right now the mod data is the current date (GMT) as a string: "yyyyMMdd",
|
* As of 0.9.16, this is essentially just an interface.
|
||||||
* and the transformation takes the original hash, appends the bytes of that mod data,
|
* Implementation moved to net.i2p.data.router.RouterKeyGenerator.
|
||||||
* then returns the SHA256 of that concatenation.
|
* No generator is available in I2PAppContext; you must be in RouterContext.
|
||||||
*
|
|
||||||
* Do we want this to simply do the XOR of the SHA256 of the current mod data and
|
|
||||||
* the key? does that provide the randomization we need? It'd save an SHA256 op.
|
|
||||||
* Bah, too much effort to think about for so little gain. Other algorithms may come
|
|
||||||
* into play layer on about making periodic updates to the routing key for data elements
|
|
||||||
* to mess with Sybil. This may be good enough though.
|
|
||||||
*
|
|
||||||
* Also - the method generateDateBasedModData() should be called after midnight GMT
|
|
||||||
* once per day to generate the correct routing keys!
|
|
||||||
*
|
|
||||||
* Warning - API subject to change. Not for use outside the router.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RoutingKeyGenerator {
|
public abstract class RoutingKeyGenerator {
|
||||||
private final Log _log;
|
|
||||||
private final I2PAppContext _context;
|
|
||||||
|
|
||||||
public RoutingKeyGenerator(I2PAppContext context) {
|
|
||||||
_log = context.logManager().getLog(RoutingKeyGenerator.class);
|
|
||||||
_context = context;
|
|
||||||
// ensure non-null mod data
|
|
||||||
generateDateBasedModData();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the generator for this context.
|
||||||
|
*
|
||||||
|
* @return null in I2PAppContext; non-null in RouterContext.
|
||||||
|
*/
|
||||||
public static RoutingKeyGenerator getInstance() {
|
public static RoutingKeyGenerator getInstance() {
|
||||||
return I2PAppContext.getGlobalContext().routingKeyGenerator();
|
return I2PAppContext.getGlobalContext().routingKeyGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile byte _currentModData[];
|
|
||||||
private volatile byte _nextModData[];
|
|
||||||
private volatile long _nextMidnight;
|
|
||||||
private volatile long _lastChanged;
|
|
||||||
|
|
||||||
private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
|
|
||||||
private static final String FORMAT = "yyyyMMdd";
|
|
||||||
private static final int LENGTH = FORMAT.length();
|
|
||||||
private final static SimpleDateFormat _fmt = new SimpleDateFormat(FORMAT, Locale.US);
|
|
||||||
static {
|
|
||||||
// make sure GMT is set, azi2phelper Vuze plugin is disabling static JVM TZ setting in Router.java
|
|
||||||
_fmt.setCalendar(_cal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current (today's) mod data.
|
* The version of the current (today's) mod data.
|
||||||
* Warning - not a copy, do not corrupt.
|
* Use to determine if the routing key should be regenerated.
|
||||||
*
|
|
||||||
* @return non-null, 8 bytes
|
|
||||||
*/
|
*/
|
||||||
public byte[] getModData() {
|
public abstract long getLastChanged();
|
||||||
return _currentModData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tomorrow's mod data.
|
* Get the routing key for a key.
|
||||||
* Warning - not a copy, do not corrupt.
|
|
||||||
* For debugging use only.
|
|
||||||
*
|
|
||||||
* @return non-null, 8 bytes
|
|
||||||
* @since 0.9.10
|
|
||||||
*/
|
|
||||||
public byte[] getNextModData() {
|
|
||||||
return _nextModData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastChanged() {
|
|
||||||
return _lastChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How long until midnight (ms)
|
|
||||||
*
|
|
||||||
* @return could be slightly negative
|
|
||||||
* @since 0.9.10 moved from UpdateRoutingKeyModifierJob
|
|
||||||
*/
|
|
||||||
public long getTimeTillMidnight() {
|
|
||||||
return _nextMidnight - _context.clock().now();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set _cal to midnight for the time given.
|
|
||||||
* Caller must synch.
|
|
||||||
* @since 0.9.10
|
|
||||||
*/
|
|
||||||
private void setCalToPreviousMidnight(long now) {
|
|
||||||
_cal.setTime(new Date(now));
|
|
||||||
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR)); // gcj <= 4.0 workaround
|
|
||||||
_cal.set(Calendar.DAY_OF_YEAR, _cal.get(Calendar.DAY_OF_YEAR)); // gcj <= 4.0 workaround
|
|
||||||
_cal.set(Calendar.HOUR_OF_DAY, 0);
|
|
||||||
_cal.set(Calendar.MINUTE, 0);
|
|
||||||
_cal.set(Calendar.SECOND, 0);
|
|
||||||
_cal.set(Calendar.MILLISECOND, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate mod data from _cal.
|
|
||||||
* Caller must synch.
|
|
||||||
* @since 0.9.10
|
|
||||||
*/
|
|
||||||
private byte[] generateModDataFromCal() {
|
|
||||||
Date today = _cal.getTime();
|
|
||||||
|
|
||||||
String modVal = _fmt.format(today);
|
|
||||||
if (modVal.length() != LENGTH)
|
|
||||||
throw new IllegalStateException();
|
|
||||||
byte[] mod = new byte[LENGTH];
|
|
||||||
for (int i = 0; i < LENGTH; i++)
|
|
||||||
mod[i] = (byte)(modVal.charAt(i) & 0xFF);
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the current modifier data with some bytes derived from the current
|
|
||||||
* date (yyyyMMdd in GMT)
|
|
||||||
*
|
|
||||||
* @return true if changed
|
|
||||||
*/
|
|
||||||
public synchronized boolean generateDateBasedModData() {
|
|
||||||
long now = _context.clock().now();
|
|
||||||
setCalToPreviousMidnight(now);
|
|
||||||
byte[] mod = generateModDataFromCal();
|
|
||||||
boolean changed = !Arrays.equals(_currentModData, mod);
|
|
||||||
if (changed) {
|
|
||||||
// add a day and store next midnight and mod data for convenience
|
|
||||||
_cal.add(Calendar.DATE, 1);
|
|
||||||
_nextMidnight = _cal.getTime().getTime();
|
|
||||||
byte[] next = generateModDataFromCal();
|
|
||||||
_currentModData = mod;
|
|
||||||
_nextModData = next;
|
|
||||||
_lastChanged = now;
|
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("Routing modifier generated: " + HexDump.dump(mod));
|
|
||||||
}
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a modified (yet consistent) hash from the origKey by generating the
|
|
||||||
* SHA256 of the targetKey with the current modData appended to it
|
|
||||||
*
|
|
||||||
* This makes Sybil's job a lot harder, as she needs to essentially take over the
|
|
||||||
* whole keyspace.
|
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if origKey is null
|
* @throws IllegalArgumentException if origKey is null
|
||||||
*/
|
*/
|
||||||
public Hash getRoutingKey(Hash origKey) {
|
public abstract Hash getRoutingKey(Hash origKey);
|
||||||
return getKey(origKey, _currentModData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the routing key using tomorrow's modData, not today's
|
|
||||||
*
|
|
||||||
* @since 0.9.10
|
|
||||||
*/
|
|
||||||
public Hash getNextRoutingKey(Hash origKey) {
|
|
||||||
return getKey(origKey, _nextModData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a modified (yet consistent) hash from the origKey by generating the
|
|
||||||
* SHA256 of the targetKey with the specified modData appended to it
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if origKey is null
|
|
||||||
*/
|
|
||||||
private static Hash getKey(Hash origKey, byte[] modData) {
|
|
||||||
if (origKey == null) throw new IllegalArgumentException("Original key is null");
|
|
||||||
byte modVal[] = new byte[Hash.HASH_LENGTH + LENGTH];
|
|
||||||
System.arraycopy(origKey.getData(), 0, modVal, 0, Hash.HASH_LENGTH);
|
|
||||||
System.arraycopy(modData, 0, modVal, Hash.HASH_LENGTH, LENGTH);
|
|
||||||
return SHA256Generator.getInstance().calculateHash(modVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****
|
|
||||||
public static void main(String args[]) {
|
|
||||||
Hash k1 = new Hash();
|
|
||||||
byte k1d[] = new byte[Hash.HASH_LENGTH];
|
|
||||||
RandomSource.getInstance().nextBytes(k1d);
|
|
||||||
k1.setData(k1d);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
System.out.println("K1: " + k1);
|
|
||||||
Hash k1m = RoutingKeyGenerator.getInstance().getRoutingKey(k1);
|
|
||||||
System.out.println("MOD: " + new String(RoutingKeyGenerator.getInstance().getModData()));
|
|
||||||
System.out.println("K1M: " + k1m);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Thread.sleep(2000);
|
|
||||||
} catch (Throwable t) { // nop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
****/
|
|
||||||
}
|
}
|
||||||
|
@@ -75,8 +75,12 @@ public class SigningPrivateKey extends SimpleDataStructure {
|
|||||||
return _type;
|
return _type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** converts this signing private key to its public equivalent
|
/**
|
||||||
* @return a SigningPublicKey object derived from this private key
|
* Converts this signing private key to its public equivalent.
|
||||||
|
* As of 0.9.16, supports all key types.
|
||||||
|
*
|
||||||
|
* @return a SigningPublicKey object derived from this private key
|
||||||
|
* @throws IllegalArgumentException on bad key or unknown or unsupported type
|
||||||
*/
|
*/
|
||||||
public SigningPublicKey toPublic() {
|
public SigningPublicKey toPublic() {
|
||||||
return KeyGenerator.getSigningPublicKey(this);
|
return KeyGenerator.getSigningPublicKey(this);
|
||||||
|
@@ -70,9 +70,12 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws UnsupportedOperationException always
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
||||||
throw new RuntimeException("go away, we dont want any");
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -101,9 +101,12 @@ public class SendMessageMessage extends I2CPMessageImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws UnsupportedOperationException always
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
||||||
throw new RuntimeException("wtf, dont run me");
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
24
installer/resources/proxy/enc-header.ht
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
HTTP/1.1 504 Gateway Timeout
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Cache-control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Proxy-Connection: close
|
||||||
|
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html><head>
|
||||||
|
<title>_("Warning: Eepsite Unreachable")</title>
|
||||||
|
<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico">
|
||||||
|
<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="logo">
|
||||||
|
<a href="http://127.0.0.1:7657/" title="_("Router Console")"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="_("I2P Router Console")" border="0"></a><hr>
|
||||||
|
<a href="http://127.0.0.1:7657/config.jsp">_("Configuration")</a> <a href="http://127.0.0.1:7657/help.jsp">_("Help")</a> <a href="http://127.0.0.1:7657/susidns/index">_("Addressbook")</a>
|
||||||
|
</div>
|
||||||
|
<div class="warning" id="warning">
|
||||||
|
<h3>_("Warning: Eepsite Unreachable")</h3>
|
||||||
|
<p>
|
||||||
|
_("The eepsite was not reachable, because it uses encryption options that are not supported by your I2P or Java version.")
|
||||||
|
<hr>
|
||||||
|
<p><b>_("Could not connect to the following destination:")</b>
|
||||||
|
</p>
|
25
installer/resources/proxy/encp-header.ht
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
HTTP/1.1 504 Gateway Timeout
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Cache-control: no-cache
|
||||||
|
Connection: close
|
||||||
|
Proxy-Connection: close
|
||||||
|
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html><head>
|
||||||
|
<title>_("Warning: Outproxy Unreachable")</title>
|
||||||
|
<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico">
|
||||||
|
<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="logo">
|
||||||
|
<a href="http://127.0.0.1:7657/" title="_("Router Console")"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="_("I2P Router Console")" border="0"></a><hr>
|
||||||
|
<a href="http://127.0.0.1:7657/config.jsp">_("Configuration")</a> <a href="http://127.0.0.1:7657/help.jsp">_("Help")</a> <a href="http://127.0.0.1:7657/susidns/index">_("Addressbook")</a>
|
||||||
|
</div>
|
||||||
|
<div class="warning" id="warning">
|
||||||
|
<h3>_("Warning: Outproxy Unreachable")</h3>
|
||||||
|
<p>
|
||||||
|
_("The HTTP outproxy was not reachable, because it uses encryption options that are not supported by your I2P or Java version.")
|
||||||
|
_("You may want to {0}retry{1} as this will randomly reselect an outproxy from the pool you have defined {2}here{3} (if you have more than one configured).", "<a href=\"javascript:parent.window.location.reload()\">", "</a>", "<a href=\"http://127.0.0.1:7657/i2ptunnel/index.jsp\">", "</a>")
|
||||||
|
_("If you continue to have trouble you may want to edit your outproxy list {0}here{1}.", "<a href=\"http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=0\">", "</a>")
|
||||||
|
</p>
|
||||||
|
<hr><p><b>_("Could not connect to the following destination:")</b></p>
|
@@ -513,6 +513,40 @@ a:active {
|
|||||||
color: #77b;
|
color: #77b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.control, a.controld {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px inset #191;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #359;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 2px 4px;
|
||||||
|
padding: 3px 4px;
|
||||||
|
text-shadow: 0px 0px #410;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.controld {
|
||||||
|
color: #459;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control img, a.controld img {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control:hover {
|
||||||
|
background-color: #559;
|
||||||
|
border: 1px outset #559;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0px 1px 5px #410;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control:active {
|
||||||
|
background: #f60 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
text-shadow: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -594,6 +628,14 @@ input[type=radio] {
|
|||||||
|
|
||||||
input.default { width: 1px; height: 1px; visibility: hidden; }
|
input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||||
|
|
||||||
|
input.disabled, input.disabled:hover {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px inset #191;
|
||||||
|
color: #459;
|
||||||
|
font-weight: normal;
|
||||||
|
text-shadow: 0px 0px 0px #410;
|
||||||
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
background: #fff !important;
|
background: #fff !important;
|
||||||
color: #22f;
|
color: #22f;
|
||||||
|
@@ -366,6 +366,10 @@ table.snarkTorrents tbody tr:hover, table.snarkDirInfo tbody tr:hover {
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.snarkFileIcon:first-child {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.snarkFileName {
|
.snarkFileName {
|
||||||
padding: 4px 0px !important;
|
padding: 4px 0px !important;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
@@ -526,6 +530,40 @@ a:hover {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.control, a.controld {
|
||||||
|
background: #989;
|
||||||
|
border: 1px inset #bbb;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #000;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 2px 4px;
|
||||||
|
padding: 3px 4px;
|
||||||
|
text-shadow: 0px 0px #410;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.controld {
|
||||||
|
color: #444;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.controld img {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control:hover {
|
||||||
|
background-color: #f60;
|
||||||
|
border: 1px outset #bbb;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0px 1px 5px #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control:active {
|
||||||
|
background: #000 !important;
|
||||||
|
color: #f60 !important;
|
||||||
|
text-shadow: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
font-size: 8.5pt;
|
font-size: 8.5pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -598,6 +636,14 @@ input[type=radio] {
|
|||||||
|
|
||||||
input.default { width: 1px; height: 1px; visibility: hidden; }
|
input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||||
|
|
||||||
|
input.disabled, input.disabled:hover {
|
||||||
|
background-color: #989;
|
||||||
|
border: 1px inset #bbb;
|
||||||
|
color: #444;
|
||||||
|
font-weight: normal;
|
||||||
|
text-shadow: 0px 0px 0px #444;
|
||||||
|
}
|
||||||
|
|
||||||
input.accept {
|
input.accept {
|
||||||
background: #989 url('../../console/images/accept.png') no-repeat 2px center;
|
background: #989 url('../../console/images/accept.png') no-repeat 2px center;
|
||||||
padding: 2px 3px 2px 20px !important;
|
padding: 2px 3px 2px 20px !important;
|
||||||
|
@@ -373,6 +373,10 @@ td:first-child {
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.snarkFileIcon:first-child {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.snarkFileName {
|
.snarkFileName {
|
||||||
padding: 4px 0px !important;
|
padding: 4px 0px !important;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
@@ -543,6 +547,40 @@ a:hover {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.control, a.controld {
|
||||||
|
background: #fef url('images/bling.png') repeat-x scroll center center;
|
||||||
|
border: 1px inset #bbb;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #f30;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 2px 4px;
|
||||||
|
padding: 3px 4px;
|
||||||
|
text-shadow: 0px 0px #410;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.controld {
|
||||||
|
color: #f60;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.controld img {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control:hover {
|
||||||
|
background-color: #fef;
|
||||||
|
border: 1px outset #bbb;
|
||||||
|
color: #f60;
|
||||||
|
text-shadow: 0px 1px 5px #fdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.control:active {
|
||||||
|
background: #000 !important;
|
||||||
|
color: #f60 !important;
|
||||||
|
text-shadow: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -612,6 +650,14 @@ input[type=radio] {
|
|||||||
|
|
||||||
input.default { width: 1px; height: 1px; visibility: hidden; }
|
input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||||
|
|
||||||
|
input.disabled, input.disabled:hover {
|
||||||
|
background-color: #989;
|
||||||
|
border: 1px inset #bbb;
|
||||||
|
color: #f60;
|
||||||
|
font-weight: normal;
|
||||||
|
text-shadow: 0px 0px 0px #410;
|
||||||
|
}
|
||||||
|
|
||||||
input.accept {
|
input.accept {
|
||||||
background: #f3efc7 url('../../console/images/accept.png') no-repeat 2px center;
|
background: #f3efc7 url('../../console/images/accept.png') no-repeat 2px center;
|
||||||
padding: 2px 3px 2px 20px !important;
|
padding: 2px 3px 2px 20px !important;
|
||||||
|
@@ -146,10 +146,10 @@ public class BuildRequestRecord {
|
|||||||
return (_data.getData()[_data.getOffset() + OFF_FLAG] & FLAG_OUTBOUND_ENDPOINT) != 0;
|
return (_data.getData()[_data.getOffset() + OFF_FLAG] & FLAG_OUTBOUND_ENDPOINT) != 0;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Time that the request was sent, truncated to the nearest hour
|
* Time that the request was sent (ms), truncated to the nearest hour
|
||||||
*/
|
*/
|
||||||
public long readRequestTime() {
|
public long readRequestTime() {
|
||||||
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * 60l * 60l * 1000l;
|
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * (60 * 60 * 1000L);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* What message ID should we send the request to the next hop with. If this is the outbound tunnel endpoint,
|
* What message ID should we send the request to the next hop with. If this is the outbound tunnel endpoint,
|
||||||
@@ -250,6 +250,8 @@ public class BuildRequestRecord {
|
|||||||
else if (isOutEndpoint)
|
else if (isOutEndpoint)
|
||||||
buf[OFF_FLAG] |= FLAG_OUTBOUND_ENDPOINT;
|
buf[OFF_FLAG] |= FLAG_OUTBOUND_ENDPOINT;
|
||||||
long truncatedHour = ctx.clock().now();
|
long truncatedHour = ctx.clock().now();
|
||||||
|
// prevent hop identification at top of the hour
|
||||||
|
truncatedHour -= ctx.random().nextInt(90*1000);
|
||||||
truncatedHour /= (60l*60l*1000l);
|
truncatedHour /= (60l*60l*1000l);
|
||||||
DataHelper.toLong(buf, OFF_REQ_TIME, 4, truncatedHour);
|
DataHelper.toLong(buf, OFF_REQ_TIME, 4, truncatedHour);
|
||||||
DataHelper.toLong(buf, OFF_SEND_MSG_ID, 4, nextMsgId);
|
DataHelper.toLong(buf, OFF_SEND_MSG_ID, 4, nextMsgId);
|
||||||
|
@@ -17,7 +17,7 @@ import java.util.Set;
|
|||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.SessionKey;
|
import net.i2p.data.SessionKey;
|
||||||
import net.i2p.data.SessionTag;
|
import net.i2p.data.SessionTag;
|
||||||
import net.i2p.data.TunnelId;
|
import net.i2p.data.TunnelId;
|
||||||
|
@@ -18,7 +18,7 @@ import net.i2p.data.DataFormatException;
|
|||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.LeaseSet;
|
import net.i2p.data.LeaseSet;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.TunnelId;
|
import net.i2p.data.TunnelId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package net.i2p.data;
|
package net.i2p.data.router;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
@@ -17,6 +17,9 @@ import java.util.Date;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
|
import net.i2p.data.DataStructureImpl;
|
||||||
import net.i2p.util.Addresses;
|
import net.i2p.util.Addresses;
|
||||||
import net.i2p.util.OrderedProperties;
|
import net.i2p.util.OrderedProperties;
|
||||||
|
|
||||||
@@ -36,6 +39,7 @@ import net.i2p.util.OrderedProperties;
|
|||||||
* several releases for the change to propagate as it is backwards-incompatible.
|
* several releases for the change to propagate as it is backwards-incompatible.
|
||||||
* Restored as of 0.9.12.
|
* Restored as of 0.9.12.
|
||||||
*
|
*
|
||||||
|
* @since 0.9.16 moved from net.i2p.data
|
||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class RouterAddress extends DataStructureImpl {
|
public class RouterAddress extends DataStructureImpl {
|
@@ -1,4 +1,7 @@
|
|||||||
package net.i2p.data;
|
package net.i2p.data.router;
|
||||||
|
|
||||||
|
import net.i2p.data.Certificate;
|
||||||
|
import net.i2p.data.KeysAndCert;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
@@ -16,6 +19,7 @@ package net.i2p.data;
|
|||||||
* As of 0.9.9 this data structure is immutable after the two keys and the certificate
|
* As of 0.9.9 this data structure is immutable after the two keys and the certificate
|
||||||
* are set; attempts to change them will throw an IllegalStateException.
|
* are set; attempts to change them will throw an IllegalStateException.
|
||||||
*
|
*
|
||||||
|
* @since 0.9.16 moved from net.i2p.data
|
||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class RouterIdentity extends KeysAndCert {
|
public class RouterIdentity extends KeysAndCert {
|
@@ -1,4 +1,4 @@
|
|||||||
package net.i2p.data;
|
package net.i2p.data.router;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* free (adj.): unencumbered; not under the control of others
|
* free (adj.): unencumbered; not under the control of others
|
||||||
@@ -31,6 +31,13 @@ import net.i2p.crypto.SHA1;
|
|||||||
import net.i2p.crypto.SHA1Hash;
|
import net.i2p.crypto.SHA1Hash;
|
||||||
import net.i2p.crypto.SHA256Generator;
|
import net.i2p.crypto.SHA256Generator;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
|
import net.i2p.data.DatabaseEntry;
|
||||||
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.data.KeysAndCert;
|
||||||
|
import net.i2p.data.Signature;
|
||||||
|
import net.i2p.data.SimpleDataStructure;
|
||||||
import net.i2p.util.Clock;
|
import net.i2p.util.Clock;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.OrderedProperties;
|
import net.i2p.util.OrderedProperties;
|
||||||
@@ -47,6 +54,7 @@ import net.i2p.util.SystemVersion;
|
|||||||
* To ensure integrity of the RouterInfo, methods that change an element of the
|
* To ensure integrity of the RouterInfo, methods that change an element of the
|
||||||
* RouterInfo will throw an IllegalStateException after the RouterInfo is signed.
|
* RouterInfo will throw an IllegalStateException after the RouterInfo is signed.
|
||||||
*
|
*
|
||||||
|
* @since 0.9.16 moved from net.i2p.data
|
||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class RouterInfo extends DatabaseEntry {
|
public class RouterInfo extends DatabaseEntry {
|
||||||
@@ -190,7 +198,7 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
||||||
// network-wide. The signature is not checked at readin time, but only
|
// network-wide. The signature is not checked at readin time, but only
|
||||||
// later, and the addresses are stored in a Set, not a List.
|
// later, and the addresses are stored in a Set, not a List.
|
||||||
DataHelper.sortStructureList(_addresses);
|
SortHelper.sortStructureList(_addresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,7 +316,7 @@ public class RouterInfo extends DatabaseEntry {
|
|||||||
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
// WARNING this sort algorithm cannot be changed, as it must be consistent
|
||||||
// network-wide. The signature is not checked at readin time, but only
|
// network-wide. The signature is not checked at readin time, but only
|
||||||
// later, and the hashes are stored in a Set, not a List.
|
// later, and the hashes are stored in a Set, not a List.
|
||||||
peers = (Collection<Hash>) DataHelper.sortStructures(peers);
|
peers = (Collection<Hash>) SortHelper.sortStructures(peers);
|
||||||
for (Hash peerHash : peers) {
|
for (Hash peerHash : peers) {
|
||||||
peerHash.writeBytes(out);
|
peerHash.writeBytes(out);
|
||||||
}
|
}
|
224
router/java/src/net/i2p/data/router/RouterKeyGenerator.java
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
package net.i2p.data.router;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.crypto.SHA256Generator;
|
||||||
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.data.RoutingKeyGenerator;
|
||||||
|
import net.i2p.util.HexDump;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component to manage the munging of hashes into routing keys - given a hash,
|
||||||
|
* perform some consistent transformation against it and return the result.
|
||||||
|
* This transformation is fed by the current "mod data".
|
||||||
|
*
|
||||||
|
* Right now the mod data is the current date (GMT) as a string: "yyyyMMdd",
|
||||||
|
* and the transformation takes the original hash, appends the bytes of that mod data,
|
||||||
|
* then returns the SHA256 of that concatenation.
|
||||||
|
*
|
||||||
|
* Do we want this to simply do the XOR of the SHA256 of the current mod data and
|
||||||
|
* the key? does that provide the randomization we need? It'd save an SHA256 op.
|
||||||
|
* Bah, too much effort to think about for so little gain. Other algorithms may come
|
||||||
|
* into play layer on about making periodic updates to the routing key for data elements
|
||||||
|
* to mess with Sybil. This may be good enough though.
|
||||||
|
*
|
||||||
|
* Also - the method generateDateBasedModData() should be called after midnight GMT
|
||||||
|
* once per day to generate the correct routing keys!
|
||||||
|
*
|
||||||
|
* @since 0.9.16 moved from net.i2p.data.RoutingKeyGenerator..
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RouterKeyGenerator extends RoutingKeyGenerator {
|
||||||
|
private final Log _log;
|
||||||
|
private final I2PAppContext _context;
|
||||||
|
|
||||||
|
public RouterKeyGenerator(I2PAppContext context) {
|
||||||
|
_log = context.logManager().getLog(RoutingKeyGenerator.class);
|
||||||
|
_context = context;
|
||||||
|
// ensure non-null mod data
|
||||||
|
generateDateBasedModData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile byte _currentModData[];
|
||||||
|
private volatile byte _nextModData[];
|
||||||
|
private volatile long _nextMidnight;
|
||||||
|
private volatile long _lastChanged;
|
||||||
|
|
||||||
|
private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||||
|
private static final String FORMAT = "yyyyMMdd";
|
||||||
|
private static final int LENGTH = FORMAT.length();
|
||||||
|
private final static SimpleDateFormat _fmt = new SimpleDateFormat(FORMAT, Locale.US);
|
||||||
|
static {
|
||||||
|
// make sure GMT is set, azi2phelper Vuze plugin is disabling static JVM TZ setting in Router.java
|
||||||
|
_fmt.setCalendar(_cal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current (today's) mod data.
|
||||||
|
* Warning - not a copy, do not corrupt.
|
||||||
|
*
|
||||||
|
* @return non-null, 8 bytes
|
||||||
|
*/
|
||||||
|
public byte[] getModData() {
|
||||||
|
return _currentModData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tomorrow's mod data.
|
||||||
|
* Warning - not a copy, do not corrupt.
|
||||||
|
* For debugging use only.
|
||||||
|
*
|
||||||
|
* @return non-null, 8 bytes
|
||||||
|
* @since 0.9.10
|
||||||
|
*/
|
||||||
|
public byte[] getNextModData() {
|
||||||
|
return _nextModData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastChanged() {
|
||||||
|
return _lastChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How long until midnight (ms)
|
||||||
|
*
|
||||||
|
* @return could be slightly negative
|
||||||
|
* @since 0.9.10 moved from UpdateRoutingKeyModifierJob
|
||||||
|
*/
|
||||||
|
public long getTimeTillMidnight() {
|
||||||
|
return _nextMidnight - _context.clock().now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set _cal to midnight for the time given.
|
||||||
|
* Caller must synch.
|
||||||
|
* @since 0.9.10
|
||||||
|
*/
|
||||||
|
private void setCalToPreviousMidnight(long now) {
|
||||||
|
_cal.setTime(new Date(now));
|
||||||
|
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR)); // gcj <= 4.0 workaround
|
||||||
|
_cal.set(Calendar.DAY_OF_YEAR, _cal.get(Calendar.DAY_OF_YEAR)); // gcj <= 4.0 workaround
|
||||||
|
_cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
_cal.set(Calendar.MINUTE, 0);
|
||||||
|
_cal.set(Calendar.SECOND, 0);
|
||||||
|
_cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate mod data from _cal.
|
||||||
|
* Caller must synch.
|
||||||
|
* @since 0.9.10
|
||||||
|
*/
|
||||||
|
private byte[] generateModDataFromCal() {
|
||||||
|
Date today = _cal.getTime();
|
||||||
|
|
||||||
|
String modVal = _fmt.format(today);
|
||||||
|
if (modVal.length() != LENGTH)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
byte[] mod = new byte[LENGTH];
|
||||||
|
for (int i = 0; i < LENGTH; i++)
|
||||||
|
mod[i] = (byte)(modVal.charAt(i) & 0xFF);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the current modifier data with some bytes derived from the current
|
||||||
|
* date (yyyyMMdd in GMT)
|
||||||
|
*
|
||||||
|
* @return true if changed
|
||||||
|
*/
|
||||||
|
public synchronized boolean generateDateBasedModData() {
|
||||||
|
long now = _context.clock().now();
|
||||||
|
setCalToPreviousMidnight(now);
|
||||||
|
byte[] mod = generateModDataFromCal();
|
||||||
|
boolean changed = !Arrays.equals(_currentModData, mod);
|
||||||
|
if (changed) {
|
||||||
|
// add a day and store next midnight and mod data for convenience
|
||||||
|
_cal.add(Calendar.DATE, 1);
|
||||||
|
_nextMidnight = _cal.getTime().getTime();
|
||||||
|
byte[] next = generateModDataFromCal();
|
||||||
|
_currentModData = mod;
|
||||||
|
_nextModData = next;
|
||||||
|
// ensure version is bumped
|
||||||
|
if (_lastChanged == now)
|
||||||
|
now++;
|
||||||
|
_lastChanged = now;
|
||||||
|
if (_log.shouldLog(Log.INFO))
|
||||||
|
_log.info("Routing modifier generated: " + HexDump.dump(mod));
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a modified (yet consistent) hash from the origKey by generating the
|
||||||
|
* SHA256 of the targetKey with the current modData appended to it
|
||||||
|
*
|
||||||
|
* This makes Sybil's job a lot harder, as she needs to essentially take over the
|
||||||
|
* whole keyspace.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if origKey is null
|
||||||
|
*/
|
||||||
|
public Hash getRoutingKey(Hash origKey) {
|
||||||
|
return getKey(origKey, _currentModData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the routing key using tomorrow's modData, not today's
|
||||||
|
*
|
||||||
|
* @since 0.9.10
|
||||||
|
*/
|
||||||
|
public Hash getNextRoutingKey(Hash origKey) {
|
||||||
|
return getKey(origKey, _nextModData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a modified (yet consistent) hash from the origKey by generating the
|
||||||
|
* SHA256 of the targetKey with the specified modData appended to it
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if origKey is null
|
||||||
|
*/
|
||||||
|
private static Hash getKey(Hash origKey, byte[] modData) {
|
||||||
|
if (origKey == null) throw new IllegalArgumentException("Original key is null");
|
||||||
|
byte modVal[] = new byte[Hash.HASH_LENGTH + LENGTH];
|
||||||
|
System.arraycopy(origKey.getData(), 0, modVal, 0, Hash.HASH_LENGTH);
|
||||||
|
System.arraycopy(modData, 0, modVal, Hash.HASH_LENGTH, LENGTH);
|
||||||
|
return SHA256Generator.getInstance().calculateHash(modVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****
|
||||||
|
public static void main(String args[]) {
|
||||||
|
Hash k1 = new Hash();
|
||||||
|
byte k1d[] = new byte[Hash.HASH_LENGTH];
|
||||||
|
RandomSource.getInstance().nextBytes(k1d);
|
||||||
|
k1.setData(k1d);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
System.out.println("K1: " + k1);
|
||||||
|
Hash k1m = RoutingKeyGenerator.getInstance().getRoutingKey(k1);
|
||||||
|
System.out.println("MOD: " + new String(RoutingKeyGenerator.getInstance().getModData()));
|
||||||
|
System.out.println("K1M: " + k1m);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (Throwable t) { // nop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
****/
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
package net.i2p.data.router;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.Destination;
|
||||||
|
import net.i2p.data.PrivateKey;
|
||||||
|
import net.i2p.data.PrivateKeyFile;
|
||||||
|
import net.i2p.data.SigningPrivateKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same format as super, simply adds a method to
|
||||||
|
* treat it as a RouterIdentity instead of a Destination.
|
||||||
|
*
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public class RouterPrivateKeyFile extends PrivateKeyFile {
|
||||||
|
|
||||||
|
public RouterPrivateKeyFile(File file) {
|
||||||
|
super(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read it in from the file.
|
||||||
|
* Also sets the local privKey and signingPrivKey.
|
||||||
|
*/
|
||||||
|
public RouterIdentity getRouterIdentity() throws IOException, DataFormatException {
|
||||||
|
InputStream in = null;
|
||||||
|
try {
|
||||||
|
in = new BufferedInputStream(new FileInputStream(this.file));
|
||||||
|
RouterIdentity ri = new RouterIdentity();
|
||||||
|
ri.readBytes(in);
|
||||||
|
privKey = new PrivateKey();
|
||||||
|
privKey.readBytes(in);
|
||||||
|
SigType type = ri.getSigningPublicKey().getType();
|
||||||
|
if (type == null)
|
||||||
|
throw new DataFormatException("Unknown sig type");
|
||||||
|
signingPrivKey = new SigningPrivateKey(type);
|
||||||
|
signingPrivKey.readBytes(in);
|
||||||
|
|
||||||
|
// set it a Destination, so we may call validateKeyPairs()
|
||||||
|
// or other methods
|
||||||
|
dest = new Destination();
|
||||||
|
dest.setPublicKey(ri.getPublicKey());
|
||||||
|
dest.setSigningPublicKey(ri.getSigningPublicKey());
|
||||||
|
dest.setCertificate(ri.getCertificate());
|
||||||
|
dest.setPadding(ri.getPadding());
|
||||||
|
|
||||||
|
return ri;
|
||||||
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
try { in.close(); } catch (IOException ioe) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
router/java/src/net/i2p/data/router/SortHelper.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package net.i2p.data.router;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.i2p.data.DataStructure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sorting of addresses in RIs
|
||||||
|
*
|
||||||
|
* @since 0.9.16 moved from DataHelper
|
||||||
|
*/
|
||||||
|
class SortHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort based on the Hash of the DataStructure.
|
||||||
|
* Warning - relatively slow.
|
||||||
|
* WARNING - this sort order must be consistent network-wide, so while the order is arbitrary,
|
||||||
|
* it cannot be changed.
|
||||||
|
* Why? Just because it has to be consistent so signing will work.
|
||||||
|
* How to spec as returning the same type as the param?
|
||||||
|
* DEPRECATED - Only used by RouterInfo.
|
||||||
|
*
|
||||||
|
* @return a new list
|
||||||
|
*/
|
||||||
|
public static List<? extends DataStructure> sortStructures(Collection<? extends DataStructure> dataStructures) {
|
||||||
|
if (dataStructures == null) return Collections.emptyList();
|
||||||
|
|
||||||
|
// This used to use Hash.toString(), which is insane, since a change to toString()
|
||||||
|
// would break the whole network. Now use Hash.toBase64().
|
||||||
|
// Note that the Base64 sort order is NOT the same as the raw byte sort order,
|
||||||
|
// despite what you may read elsewhere.
|
||||||
|
|
||||||
|
//ArrayList<DataStructure> rv = new ArrayList(dataStructures.size());
|
||||||
|
//TreeMap<String, DataStructure> tm = new TreeMap();
|
||||||
|
//for (DataStructure struct : dataStructures) {
|
||||||
|
// tm.put(struct.calculateHash().toString(), struct);
|
||||||
|
//}
|
||||||
|
//for (DataStructure struct : tm.values()) {
|
||||||
|
// rv.add(struct);
|
||||||
|
//}
|
||||||
|
ArrayList<DataStructure> rv = new ArrayList<DataStructure>(dataStructures);
|
||||||
|
sortStructureList(rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See above.
|
||||||
|
* DEPRECATED - Only used by RouterInfo.
|
||||||
|
*
|
||||||
|
* @since 0.9
|
||||||
|
*/
|
||||||
|
static void sortStructureList(List<? extends DataStructure> dataStructures) {
|
||||||
|
Collections.sort(dataStructures, new DataStructureComparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See sortStructures() comments.
|
||||||
|
* @since 0.8.3
|
||||||
|
*/
|
||||||
|
private static class DataStructureComparator implements Comparator<DataStructure>, Serializable {
|
||||||
|
public int compare(DataStructure l, DataStructure r) {
|
||||||
|
return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
router/java/src/net/i2p/data/router/package.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Classes formerly in net.i2p.data but moved here as they are only used by the router.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -28,8 +28,8 @@ import java.util.TreeSet;
|
|||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
||||||
import net.i2p.util.Addresses;
|
import net.i2p.util.Addresses;
|
||||||
import net.i2p.util.ConcurrentHashSet;
|
import net.i2p.util.ConcurrentHashSet;
|
||||||
|
@@ -13,7 +13,7 @@ import java.io.Writer;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the communication subsystem between peers, including connections,
|
* Manages the communication subsystem between peers, including connections,
|
||||||
|
@@ -9,7 +9,7 @@ package net.i2p.router;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterIdentity;
|
import net.i2p.data.router.RouterIdentity;
|
||||||
import net.i2p.data.i2np.I2NPMessage;
|
import net.i2p.data.i2np.I2NPMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -14,7 +14,7 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterIdentity;
|
import net.i2p.data.router.RouterIdentity;
|
||||||
import net.i2p.data.i2np.DatabaseLookupMessage;
|
import net.i2p.data.i2np.DatabaseLookupMessage;
|
||||||
import net.i2p.data.i2np.DatabaseSearchReplyMessage;
|
import net.i2p.data.i2np.DatabaseSearchReplyMessage;
|
||||||
import net.i2p.data.i2np.DeliveryStatusMessage;
|
import net.i2p.data.i2np.DeliveryStatusMessage;
|
||||||
|
@@ -18,6 +18,7 @@ import java.io.OutputStream;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.DataStructure;
|
import net.i2p.data.DataStructure;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
@@ -26,6 +27,7 @@ import net.i2p.data.PrivateKey;
|
|||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
import net.i2p.data.SigningPrivateKey;
|
import net.i2p.data.SigningPrivateKey;
|
||||||
import net.i2p.data.SigningPublicKey;
|
import net.i2p.data.SigningPublicKey;
|
||||||
|
import net.i2p.router.startup.CreateRouterInfoJob;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.SecureDirectory;
|
import net.i2p.util.SecureDirectory;
|
||||||
import net.i2p.util.SecureFileOutputStream;
|
import net.i2p.util.SecureFileOutputStream;
|
||||||
@@ -47,10 +49,10 @@ public class KeyManager {
|
|||||||
|
|
||||||
public final static String PROP_KEYDIR = "router.keyBackupDir";
|
public final static String PROP_KEYDIR = "router.keyBackupDir";
|
||||||
public final static String DEFAULT_KEYDIR = "keyBackup";
|
public final static String DEFAULT_KEYDIR = "keyBackup";
|
||||||
private final static String KEYFILE_PRIVATE_ENC = "privateEncryption.key";
|
public final static String KEYFILE_PRIVATE_ENC = "privateEncryption.key";
|
||||||
private final static String KEYFILE_PUBLIC_ENC = "publicEncryption.key";
|
public final static String KEYFILE_PUBLIC_ENC = "publicEncryption.key";
|
||||||
private final static String KEYFILE_PRIVATE_SIGNING = "privateSigning.key";
|
public final static String KEYFILE_PRIVATE_SIGNING = "privateSigning.key";
|
||||||
private final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key";
|
public final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key";
|
||||||
|
|
||||||
public KeyManager(RouterContext context) {
|
public KeyManager(RouterContext context) {
|
||||||
_context = context;
|
_context = context;
|
||||||
@@ -151,8 +153,9 @@ public class KeyManager {
|
|||||||
private void syncKeys(File keyDir) {
|
private void syncKeys(File keyDir) {
|
||||||
syncPrivateKey(keyDir);
|
syncPrivateKey(keyDir);
|
||||||
syncPublicKey(keyDir);
|
syncPublicKey(keyDir);
|
||||||
syncSigningKey(keyDir);
|
SigType type = CreateRouterInfoJob.getSigTypeConfig(getContext());
|
||||||
syncVerificationKey(keyDir);
|
syncSigningKey(keyDir, type);
|
||||||
|
syncVerificationKey(keyDir, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncPrivateKey(File keyDir) {
|
private void syncPrivateKey(File keyDir) {
|
||||||
@@ -181,27 +184,33 @@ public class KeyManager {
|
|||||||
_publicKey = (PublicKey) readin;
|
_publicKey = (PublicKey) readin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncSigningKey(File keyDir) {
|
/**
|
||||||
|
* @param type the SigType to expect on read-in, ignored on write
|
||||||
|
*/
|
||||||
|
private void syncSigningKey(File keyDir, SigType type) {
|
||||||
DataStructure ds;
|
DataStructure ds;
|
||||||
File keyFile = new File(keyDir, KEYFILE_PRIVATE_SIGNING);
|
File keyFile = new File(keyDir, KEYFILE_PRIVATE_SIGNING);
|
||||||
boolean exists = (_signingPrivateKey != null);
|
boolean exists = (_signingPrivateKey != null);
|
||||||
if (exists)
|
if (exists)
|
||||||
ds = _signingPrivateKey;
|
ds = _signingPrivateKey;
|
||||||
else
|
else
|
||||||
ds = new SigningPrivateKey();
|
ds = new SigningPrivateKey(type);
|
||||||
DataStructure readin = syncKey(keyFile, ds, exists);
|
DataStructure readin = syncKey(keyFile, ds, exists);
|
||||||
if (readin != null && !exists)
|
if (readin != null && !exists)
|
||||||
_signingPrivateKey = (SigningPrivateKey) readin;
|
_signingPrivateKey = (SigningPrivateKey) readin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncVerificationKey(File keyDir) {
|
/**
|
||||||
|
* @param type the SigType to expect on read-in, ignored on write
|
||||||
|
*/
|
||||||
|
private void syncVerificationKey(File keyDir, SigType type) {
|
||||||
DataStructure ds;
|
DataStructure ds;
|
||||||
File keyFile = new File(keyDir, KEYFILE_PUBLIC_SIGNING);
|
File keyFile = new File(keyDir, KEYFILE_PUBLIC_SIGNING);
|
||||||
boolean exists = (_signingPublicKey != null);
|
boolean exists = (_signingPublicKey != null);
|
||||||
if (exists)
|
if (exists)
|
||||||
ds = _signingPublicKey;
|
ds = _signingPublicKey;
|
||||||
else
|
else
|
||||||
ds = new SigningPublicKey();
|
ds = new SigningPublicKey(type);
|
||||||
DataStructure readin = syncKey(keyFile, ds, exists);
|
DataStructure readin = syncKey(keyFile, ds, exists);
|
||||||
if (readin != null && !exists)
|
if (readin != null && !exists)
|
||||||
_signingPublicKey = (SigningPublicKey) readin;
|
_signingPublicKey = (SigningPublicKey) readin;
|
||||||
|
@@ -40,7 +40,7 @@ public class LeaseSetKeys {
|
|||||||
/**
|
/**
|
||||||
* Key with which a LeaseSet can be revoked (by republishing it with no Leases)
|
* Key with which a LeaseSet can be revoked (by republishing it with no Leases)
|
||||||
*
|
*
|
||||||
* @deprecated unused
|
* Deprecated, unused
|
||||||
*/
|
*/
|
||||||
public SigningPrivateKey getRevocationKey() { return _revocationKey; }
|
public SigningPrivateKey getRevocationKey() { return _revocationKey; }
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import java.util.Scanner;
|
|||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -14,9 +14,10 @@ import java.util.Collections;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.data.DatabaseEntry;
|
import net.i2p.data.DatabaseEntry;
|
||||||
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.LeaseSet;
|
import net.i2p.data.LeaseSet;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.networkdb.reseed.ReseedChecker;
|
import net.i2p.router.networkdb.reseed.ReseedChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,18 +52,51 @@ public abstract class NetworkDatabaseFacade implements Service {
|
|||||||
public abstract LeaseSet lookupLeaseSetLocally(Hash key);
|
public abstract LeaseSet lookupLeaseSetLocally(Hash key);
|
||||||
public abstract void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs);
|
public abstract void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs);
|
||||||
public abstract RouterInfo lookupRouterInfoLocally(Hash key);
|
public abstract RouterInfo lookupRouterInfoLocally(Hash key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup using the client's tunnels
|
||||||
|
* Succeeds even if LS validation fails due to unsupported sig type
|
||||||
|
*
|
||||||
|
* @param fromLocalDest use these tunnels for the lookup, or null for exploratory
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public abstract void lookupDestination(Hash key, Job onFinishedJob, long timeoutMs, Hash fromLocalDest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup locally in netDB and in badDest cache
|
||||||
|
* Succeeds even if LS validation failed due to unsupported sig type
|
||||||
|
*
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public abstract Destination lookupDestinationLocally(Hash key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the leaseSet if another leaseSet already existed at that key
|
* @return the leaseSet if another leaseSet already existed at that key
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if the data is not valid
|
* @throws IllegalArgumentException if the data is not valid
|
||||||
*/
|
*/
|
||||||
public abstract LeaseSet store(Hash key, LeaseSet leaseSet) throws IllegalArgumentException;
|
public abstract LeaseSet store(Hash key, LeaseSet leaseSet) throws IllegalArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the routerInfo if another router already existed at that key
|
* @return the routerInfo if another router already existed at that key
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if the data is not valid
|
* @throws IllegalArgumentException if the data is not valid
|
||||||
*/
|
*/
|
||||||
public abstract RouterInfo store(Hash key, RouterInfo routerInfo) throws IllegalArgumentException;
|
public abstract RouterInfo store(Hash key, RouterInfo routerInfo) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the old entry if it already existed at that key
|
||||||
|
* @throws IllegalArgumentException if the data is not valid
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public DatabaseEntry store(Hash key, DatabaseEntry entry) throws IllegalArgumentException {
|
||||||
|
if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO)
|
||||||
|
return store(key, (RouterInfo) entry);
|
||||||
|
if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET)
|
||||||
|
return store(key, (LeaseSet) entry);
|
||||||
|
throw new IllegalArgumentException("unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws IllegalArgumentException if the local router is not valid
|
* @throws IllegalArgumentException if the local router is not valid
|
||||||
*/
|
*/
|
||||||
@@ -101,4 +135,12 @@ public abstract class NetworkDatabaseFacade implements Service {
|
|||||||
* @since IPv6
|
* @since IPv6
|
||||||
*/
|
*/
|
||||||
public boolean floodfillEnabled() { return false; };
|
public boolean floodfillEnabled() { return false; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is it permanently negative cached?
|
||||||
|
*
|
||||||
|
* @param key only for Destinations; for RouterIdentities, see Banlist
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public boolean isNegativeCachedForever(Hash key) { return false; }
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.i2np.I2NPMessage;
|
import net.i2p.data.i2np.I2NPMessage;
|
||||||
import net.i2p.router.util.CDPQEntry;
|
import net.i2p.router.util.CDPQEntry;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
@@ -70,9 +70,8 @@ public class PersistentKeyRing extends KeyRing {
|
|||||||
Hash h = e.getKey();
|
Hash h = e.getKey();
|
||||||
buf.append(h.toBase64().substring(0, 6)).append("…");
|
buf.append(h.toBase64().substring(0, 6)).append("…");
|
||||||
buf.append("<td>");
|
buf.append("<td>");
|
||||||
LeaseSet ls = _ctx.netDb().lookupLeaseSetLocally(h);
|
Destination dest = _ctx.netDb().lookupDestinationLocally(h);
|
||||||
if (ls != null) {
|
if (dest != null) {
|
||||||
Destination dest = ls.getDestination();
|
|
||||||
if (_ctx.clientManager().isLocal(dest)) {
|
if (_ctx.clientManager().isLocal(dest)) {
|
||||||
TunnelPoolSettings in = _ctx.tunnelManager().getInboundSettings(h);
|
TunnelPoolSettings in = _ctx.tunnelManager().getInboundSettings(h);
|
||||||
if (in != null && in.getDestinationNickname() != null)
|
if (in != null && in.getDestinationNickname() != null)
|
||||||
|
@@ -29,11 +29,12 @@ import net.i2p.data.Certificate;
|
|||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.data.SigningPrivateKey;
|
import net.i2p.data.SigningPrivateKey;
|
||||||
import net.i2p.data.i2np.GarlicMessage;
|
import net.i2p.data.i2np.GarlicMessage;
|
||||||
import net.i2p.router.message.GarlicMessageHandler;
|
import net.i2p.router.message.GarlicMessageHandler;
|
||||||
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
|
||||||
|
import net.i2p.router.startup.CreateRouterInfoJob;
|
||||||
import net.i2p.router.startup.StartupJob;
|
import net.i2p.router.startup.StartupJob;
|
||||||
import net.i2p.router.startup.WorkingDir;
|
import net.i2p.router.startup.WorkingDir;
|
||||||
import net.i2p.router.tasks.*;
|
import net.i2p.router.tasks.*;
|
||||||
@@ -98,10 +99,6 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
/** this does not put an 'H' in your routerInfo **/
|
/** this does not put an 'H' in your routerInfo **/
|
||||||
public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
|
public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
|
||||||
public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
|
public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
|
||||||
public final static String PROP_INFO_FILENAME = "router.info.location";
|
|
||||||
public final static String PROP_INFO_FILENAME_DEFAULT = "router.info";
|
|
||||||
public final static String PROP_KEYS_FILENAME = "router.keys.location";
|
|
||||||
public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys";
|
|
||||||
public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
|
public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress";
|
||||||
public final static String DNS_CACHE_TIME = "" + (5*60);
|
public final static String DNS_CACHE_TIME = "" + (5*60);
|
||||||
private static final String EVENTLOG = "eventlog.txt";
|
private static final String EVENTLOG = "eventlog.txt";
|
||||||
@@ -672,20 +669,6 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
return Boolean.parseBoolean(h);
|
return Boolean.parseBoolean(h);
|
||||||
return _context.commSystem().isInBadCountry();
|
return _context.commSystem().isInBadCountry();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob.
|
|
||||||
* Not called by periodic RepublishLocalRouterInfoJob.
|
|
||||||
* We don't want to change the cert on the fly as it changes the router hash.
|
|
||||||
* RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert.
|
|
||||||
* There's no reason to ever add a hidden cert?
|
|
||||||
* @return the certificate for a new RouterInfo - probably a null cert.
|
|
||||||
*/
|
|
||||||
public Certificate createCertificate() {
|
|
||||||
if (_context.getBooleanProperty(PROP_HIDDEN))
|
|
||||||
return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null);
|
|
||||||
return Certificate.NULL_CERT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 0.9.3
|
* @since 0.9.3
|
||||||
@@ -698,16 +681,18 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
* Ugly list of files that we need to kill if we are building a new identity
|
* Ugly list of files that we need to kill if we are building a new identity
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final String _rebuildFiles[] = new String[] { "router.info",
|
private static final String _rebuildFiles[] = new String[] {
|
||||||
"router.keys",
|
CreateRouterInfoJob.INFO_FILENAME,
|
||||||
"netDb/my.info", // no longer used
|
CreateRouterInfoJob.KEYS_FILENAME,
|
||||||
"connectionTag.keys", // never used?
|
CreateRouterInfoJob.KEYS2_FILENAME,
|
||||||
"keyBackup/privateEncryption.key",
|
"netDb/my.info", // no longer used
|
||||||
"keyBackup/privateSigning.key",
|
"connectionTag.keys", // never used?
|
||||||
"keyBackup/publicEncryption.key",
|
KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PRIVATE_ENC,
|
||||||
"keyBackup/publicSigning.key",
|
KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PUBLIC_ENC,
|
||||||
"sessionKeys.dat" // no longer used
|
KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PRIVATE_SIGNING,
|
||||||
};
|
KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PUBLIC_SIGNING,
|
||||||
|
"sessionKeys.dat" // no longer used
|
||||||
|
};
|
||||||
|
|
||||||
public void killKeys() {
|
public void killKeys() {
|
||||||
//new Exception("Clearing identity files").printStackTrace();
|
//new Exception("Clearing identity files").printStackTrace();
|
||||||
@@ -1085,7 +1070,7 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
return;
|
return;
|
||||||
_eventLog.addEvent(EventLog.CLOCK_SHIFT, Long.toString(delta));
|
_eventLog.addEvent(EventLog.CLOCK_SHIFT, Long.toString(delta));
|
||||||
// update the routing key modifier
|
// update the routing key modifier
|
||||||
_context.routingKeyGenerator().generateDateBasedModData();
|
_context.routerKeyGenerator().generateDateBasedModData();
|
||||||
if (_context.commSystem().countActivePeers() <= 0)
|
if (_context.commSystem().countActivePeers() <= 0)
|
||||||
return;
|
return;
|
||||||
if (delta > 0)
|
if (delta > 0)
|
||||||
|
@@ -10,7 +10,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.app.ClientAppManager;
|
import net.i2p.app.ClientAppManager;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.RouterInfo;
|
import net.i2p.data.RoutingKeyGenerator;
|
||||||
|
import net.i2p.data.router.RouterInfo;
|
||||||
|
import net.i2p.data.router.RouterKeyGenerator;
|
||||||
import net.i2p.internal.InternalClientManager;
|
import net.i2p.internal.InternalClientManager;
|
||||||
import net.i2p.router.client.ClientManagerFacadeImpl;
|
import net.i2p.router.client.ClientManagerFacadeImpl;
|
||||||
import net.i2p.router.crypto.TransientSessionKeyManager;
|
import net.i2p.router.crypto.TransientSessionKeyManager;
|
||||||
@@ -65,6 +67,7 @@ public class RouterContext extends I2PAppContext {
|
|||||||
//private MessageStateMonitor _messageStateMonitor;
|
//private MessageStateMonitor _messageStateMonitor;
|
||||||
private RouterThrottle _throttle;
|
private RouterThrottle _throttle;
|
||||||
private RouterAppManager _appManager;
|
private RouterAppManager _appManager;
|
||||||
|
private RouterKeyGenerator _routingKeyGenerator;
|
||||||
private final Set<Runnable> _finalShutdownTasks;
|
private final Set<Runnable> _finalShutdownTasks;
|
||||||
// split up big lock on this to avoid deadlocks
|
// split up big lock on this to avoid deadlocks
|
||||||
private volatile boolean _initialized;
|
private volatile boolean _initialized;
|
||||||
@@ -183,6 +186,7 @@ public class RouterContext extends I2PAppContext {
|
|||||||
_messageHistory = new MessageHistory(this);
|
_messageHistory = new MessageHistory(this);
|
||||||
_messageRegistry = new OutboundMessageRegistry(this);
|
_messageRegistry = new OutboundMessageRegistry(this);
|
||||||
//_messageStateMonitor = new MessageStateMonitor(this);
|
//_messageStateMonitor = new MessageStateMonitor(this);
|
||||||
|
_routingKeyGenerator = new RouterKeyGenerator(this);
|
||||||
if (!getBooleanProperty("i2p.dummyNetDb"))
|
if (!getBooleanProperty("i2p.dummyNetDb"))
|
||||||
_netDb = new FloodfillNetworkDatabaseFacade(this); // new KademliaNetworkDatabaseFacade(this);
|
_netDb = new FloodfillNetworkDatabaseFacade(this); // new KademliaNetworkDatabaseFacade(this);
|
||||||
else
|
else
|
||||||
@@ -582,4 +586,35 @@ public class RouterContext extends I2PAppContext {
|
|||||||
_sessionKeyManagerInitialized = true;
|
_sessionKeyManagerInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine how much do we want to mess with the keys to turn them
|
||||||
|
* into something we can route. This is context specific because we
|
||||||
|
* may want to test out how things react when peers don't agree on
|
||||||
|
* how to skew.
|
||||||
|
*
|
||||||
|
* Returns same thing as routerKeyGenerator()
|
||||||
|
*
|
||||||
|
* @return non-null
|
||||||
|
* @since 0.9.16 Overrides I2PAppContext. Returns non-null in RouterContext and null in I2PAppcontext.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public RoutingKeyGenerator routingKeyGenerator() {
|
||||||
|
return _routingKeyGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine how much do we want to mess with the keys to turn them
|
||||||
|
* into something we can route. This is context specific because we
|
||||||
|
* may want to test out how things react when peers don't agree on
|
||||||
|
* how to skew.
|
||||||
|
*
|
||||||
|
* Returns same thing as routingKeyGenerator()
|
||||||
|
*
|
||||||
|
* @return non-null
|
||||||
|
* @since 0.9.16
|
||||||
|
*/
|
||||||
|
public RouterKeyGenerator routerKeyGenerator() {
|
||||||
|
return _routingKeyGenerator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|