forked from I2P_Developers/i2p.i2p
Addressbook: Add tests for Daemon to read local subscription file
More HostTxtEntry 'remove' methods and tests
This commit is contained in:
@@ -177,6 +177,18 @@ class AddressBook implements Iterable<Map.Entry<String, HostTxtEntry>> {
|
||||
this.subFile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test only.
|
||||
*
|
||||
* @param testsubfile path to a file containing the simulated fetch of a subscription
|
||||
* @since 0.9.26
|
||||
*/
|
||||
public AddressBook(String testsubfile) {
|
||||
this.location = testsubfile;
|
||||
this.addresses = null;
|
||||
this.subFile = new File(testsubfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator over the addresses in the AddressBook.
|
||||
* @since 0.8.7
|
||||
|
@@ -737,7 +737,24 @@ public class Daemon {
|
||||
* others are ignored.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
_instance.run(args);
|
||||
if (args != null && args.length > 0 && args[0].equals("test"))
|
||||
_instance.test(args);
|
||||
else
|
||||
_instance.run(args);
|
||||
}
|
||||
|
||||
/** @since 0.9.26 */
|
||||
private static void test(String[] args) {
|
||||
Properties ctxProps = new Properties();
|
||||
String PROP_FORCE = "i2p.naming.blockfile.writeInAppContext";
|
||||
ctxProps.setProperty(PROP_FORCE, "true");
|
||||
I2PAppContext ctx = new I2PAppContext(ctxProps);
|
||||
NamingService ns = getNamingService("hosts.txt");
|
||||
File published = new File("test-published.txt");
|
||||
Log log = new Log(new File("test-log.txt"));
|
||||
SubscriptionList subscriptions = new SubscriptionList("test-sub.txt");
|
||||
update(ns, published, subscriptions, log);
|
||||
ctx.logManager().flush();
|
||||
}
|
||||
|
||||
public void run(String[] args) {
|
||||
|
@@ -71,9 +71,16 @@ class HostTxtEntry {
|
||||
* @throws IllegalArgumentException on dup key in sprops and other errors
|
||||
*/
|
||||
public HostTxtEntry(String name, String dest, String sprops) throws IllegalArgumentException {
|
||||
this.name = name;
|
||||
this.dest = dest;
|
||||
this.props = parseProps(sprops);
|
||||
this(name, dest, parseProps(sprops));
|
||||
}
|
||||
|
||||
/**
|
||||
* A 'remove' entry. Name and Dest will be null.
|
||||
* @param sprops line part after the #!, non-null
|
||||
* @throws IllegalArgumentException on dup key in sprops and other errors
|
||||
*/
|
||||
public HostTxtEntry(String sprops) throws IllegalArgumentException {
|
||||
this(null, null, parseProps(sprops));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,19 +139,19 @@ class HostTxtEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write as a "remove" line #!olddest=dest#oldname=name#k1=v1#k2=v2...]
|
||||
* Write as a "remove" line #!dest=dest#name=name#k1=v1#sig=sig...]
|
||||
* Includes newline.
|
||||
* Must have been constructed with non-null properties.
|
||||
*/
|
||||
public void writeRemove(BufferedWriter out) throws IOException {
|
||||
if (props == null)
|
||||
throw new IllegalStateException();
|
||||
props.setProperty(PROP_OLDNAME, name);
|
||||
props.setProperty(PROP_OLDDEST, dest);
|
||||
props.setProperty(PROP_NAME, name);
|
||||
props.setProperty(PROP_DEST, dest);
|
||||
writeProps(out, false, false);
|
||||
out.newLine();
|
||||
props.remove(PROP_OLDNAME);
|
||||
props.remove(PROP_OLDDEST);
|
||||
props.remove(PROP_NAME);
|
||||
props.remove(PROP_DEST);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,6 +272,50 @@ class HostTxtEntry {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify with the "dest" property's public key using the "sig" property
|
||||
*/
|
||||
public boolean hasValidRemoveSig() {
|
||||
if (props == null)
|
||||
return false;
|
||||
boolean rv = false;
|
||||
// don't cache result
|
||||
if (true) {
|
||||
StringWriter buf = new StringWriter(1024);
|
||||
String sig = props.getProperty(PROP_SIG);
|
||||
String olddest = props.getProperty(PROP_DEST);
|
||||
if (sig == null || olddest == null)
|
||||
return false;
|
||||
try {
|
||||
writeProps(buf, true, true);
|
||||
} catch (IOException ioe) {
|
||||
// won't happen
|
||||
return false;
|
||||
}
|
||||
byte[] sdata = Base64.decode(sig);
|
||||
if (sdata == null)
|
||||
return false;
|
||||
Destination d;
|
||||
try {
|
||||
d = new Destination(olddest);
|
||||
} catch (DataFormatException dfe) {
|
||||
return false;
|
||||
}
|
||||
SigningPublicKey spk = d.getSigningPublicKey();
|
||||
SigType type = spk.getType();
|
||||
if (type == null)
|
||||
return false;
|
||||
Signature s;
|
||||
try {
|
||||
s = new Signature(type, sdata);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
return false;
|
||||
}
|
||||
rv = DSAEngine.getInstance().verifySignature(s, DataHelper.getUTF8(buf.toString()), spk);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return dest.hashCode();
|
||||
@@ -299,6 +350,30 @@ class HostTxtEntry {
|
||||
signIt(spk, PROP_OLDSIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign as a "remove" line #!dest=dest#name=name#k1=v1#sig=sig...]
|
||||
*/
|
||||
public void signRemove(SigningPrivateKey spk) {
|
||||
if (props == null)
|
||||
throw new IllegalStateException();
|
||||
if (props.containsKey(PROP_SIG))
|
||||
throw new IllegalStateException();
|
||||
props.setProperty(PROP_NAME, name);
|
||||
props.setProperty(PROP_DEST, dest);
|
||||
StringWriter buf = new StringWriter(1024);
|
||||
try {
|
||||
writeProps(buf, false, false);
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalStateException(ioe);
|
||||
}
|
||||
props.remove(PROP_NAME);
|
||||
props.remove(PROP_DEST);
|
||||
Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk);
|
||||
if (s == null)
|
||||
throw new IllegalArgumentException("sig failed");
|
||||
props.setProperty(PROP_SIG, s.toBase64());
|
||||
}
|
||||
|
||||
/**
|
||||
* for testing only
|
||||
* @param sigprop The signature property to set
|
||||
@@ -384,6 +459,22 @@ class HostTxtEntry {
|
||||
throw new IllegalStateException("Inner fail 2");
|
||||
if (!he2.hasValidSig())
|
||||
throw new IllegalStateException("Outer fail 2");
|
||||
|
||||
// 'remove' tests (corrupts earlier sigs)
|
||||
he.getProps().remove(PROP_SIG);
|
||||
he.signRemove(priv);
|
||||
//out.write("Remove entry:\n");
|
||||
sw = new StringWriter(1024);
|
||||
buf = new BufferedWriter(sw);
|
||||
he.writeRemove(buf);
|
||||
buf.flush();
|
||||
out.write(sw.toString());
|
||||
out.flush();
|
||||
line = sw.toString().substring(2).trim();
|
||||
HostTxtEntry he3 = new HostTxtEntry(line);
|
||||
if (!he3.hasValidRemoveSig())
|
||||
throw new IllegalStateException("Remove verify fail");
|
||||
|
||||
//out.write("Test passed\n");
|
||||
//out.flush();
|
||||
}
|
||||
|
@@ -75,7 +75,10 @@ class SubscriptionIterator implements Iterator<AddressBook> {
|
||||
*/
|
||||
public AddressBook next() {
|
||||
Subscription sub = this.subIterator.next();
|
||||
if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now() &&
|
||||
if (sub.getLocation().startsWith("file:")) {
|
||||
// test only
|
||||
return new AddressBook(sub.getLocation().substring(5));
|
||||
} else if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now() &&
|
||||
I2PAppContext.getGlobalContext().portMapper().getPort(PortMapper.SVC_HTTP_PROXY) >= 0 &&
|
||||
!I2PAppContext.getGlobalContext().getBooleanProperty("i2p.vmCommSystem")) {
|
||||
//System.err.println("Fetching addressbook from " + sub.getLocation());
|
||||
|
@@ -100,6 +100,24 @@ class SubscriptionList implements Iterable<AddressBook> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing only.
|
||||
*
|
||||
* @param hoststxt path to a local file used as the test 'subscription' input
|
||||
* @since 0.9.26
|
||||
*/
|
||||
public SubscriptionList(String hoststxt) {
|
||||
File dummy = new File("/dev/null");
|
||||
this.etagsFile = dummy;
|
||||
this.lastModifiedFile = dummy;
|
||||
this.lastFetchedFile = dummy;
|
||||
this.delay = 0;
|
||||
this.proxyHost = "127.0.0.1";
|
||||
this.proxyPort = 4444;
|
||||
Subscription sub = new Subscription("file:" + hoststxt, null, null, null);
|
||||
this.subscriptions = Collections.singletonList(sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator over the AddressBooks represented by the Subscriptions
|
||||
* in this SubscriptionList.
|
||||
|
Reference in New Issue
Block a user