Addressbook: Fix changedest action

- Implement adddest action
- Logging improvements
BFNS: Fix lookupAll() NPE
- Fix addDestination() UOE
- Support long property values
DataHelper: Properties methods cleanup
HostTxtEntry: Test improvements
This commit is contained in:
zzz
2016-04-22 23:37:55 +00:00
parent 55de82bb50
commit 75dd22510b
4 changed files with 319 additions and 146 deletions

View File

@ -202,40 +202,50 @@ public class Daemon {
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) {
Destination pod = new Destination(polddest);
// fill in oldDest for .txt naming service
if (isKnown && isTextFile)
oldDest = router.lookup(key);
if (pod.equals(dest)) {
// invalid
if (log != null)
log.append("Action: " + action + " failed because" +
" identical old and new destinations for " + key +
" from " + addressbook.getLocation());
invalid++;
continue;
} else if (!isKnown) {
List<Destination> pod2 = router.lookupAll(key);
if (pod2 == null) {
// we didn't know it before, so we'll add it
} else if (dest.equals(oldDest)) {
// TODO check inner sig anyway?
} else if (pod2.contains(dest)) {
// we knew it before, with the same dest
old++;
continue;
} else if (pod.equals(oldDest)) {
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
if (log != null)
log.append("Action: " + action + " failed because" +
" inner signature for key " + key +
" failed" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
// TODO Requires NamingService support
// if (isTextFile), do we replace or not? check sigType.isAvailable()
// router.addAltDest(dest)
if (log != null)
log.append("Action: " + action + " unimplemented" +
" from " + addressbook.getLocation());
boolean success = router.addDestination(key, dest, props);
if (log != null) {
if (success)
log.append("Additional address for " + key +
" added to address book. From: " + addressbook.getLocation());
else
log.append("Failed to add additional address for " + key +
" From: " + addressbook.getLocation());
}
// now update the published addressbook
// ditto
if (published != null) {
if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.addDestination(key, dest, props);
if (log != null && !success)
log.append("Add to published address book " + published.getAbsolutePath() + " failed for " + key);
}
nnew++;
continue;
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, he.getDest(), addressbook);
invalid++;
continue;
}
@ -261,18 +271,14 @@ public class Daemon {
// checks out, so we'll add the new one
} else {
// mismatch, disallow
if (log != null)
log.append("Action: " + action + " failed because" +
" destination for old name " + poldname +
" does not match" +
" from " + addressbook.getLocation());
logMismatch(log, action, key, pod, he.getDest(), addressbook);
invalid++;
continue;
}
} else {
if (log != null)
log.append("Action: " + action + " failed, missing required parameters" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
@ -292,7 +298,7 @@ public class Daemon {
log.append("Action: " + action + " failed because" +
" old name " + poldname +
" is invalid" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
@ -300,6 +306,7 @@ public class Daemon {
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 == null) {
// we didn't have the old name
// TODO check inner sig anyway?
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
@ -307,24 +314,20 @@ public class Daemon {
log.append("Action: " + action + " failed because" +
" inner signature for old name " + poldname +
" failed" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
} else {
// mismatch, disallow
if (log != null)
log.append("Action: " + action + " failed because" +
" destination for old name " + poldname +
" does not match provided" +
" from " + addressbook.getLocation());
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
continue;
}
} else {
if (log != null)
log.append("Action: " + action + " failed, missing required parameters" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
@ -335,37 +338,44 @@ public class Daemon {
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) {
Destination pod = new Destination(polddest);
// fill in oldDest for .txt naming service
if (isKnown && isTextFile)
oldDest = router.lookup(key);
if (!isKnown) {
List<Destination> pod2 = router.lookupAll(key);
if (pod2 == null) {
// we didn't have the old name
} else if (pod.equals(oldDest)) {
// TODO check inner sig anyway?
} else if (pod2.contains(dest)) {
// we already have the new dest
old++;
continue;
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
if (log != null)
log.append("Action: " + action + " failed because" +
" inner signature for key " + key +
" failed" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
if (log != null) {
if (pod2.size() == 1)
log.append("Changing destination for " + key +
". From: " + addressbook.getLocation());
else
log.append("Replacing " + pod2.size() + " destinations for " + key +
". From: " + addressbook.getLocation());
}
// TODO set flag to do non-putifabsent for published below
} else {
// mismatch, disallow
if (log != null)
log.append("Action: " + action + " failed because" +
" destination for key " + key +
" does not match provided" +
" from " + addressbook.getLocation());
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
continue;
}
} else {
if (log != null)
log.append("Action: " + action + " failed, missing required parameters" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
@ -393,11 +403,11 @@ public class Daemon {
if (success)
log.append("Removed: " + poldname +
" to be replaced with " + key +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname +
" to be replaced with " + key +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (published != null) {
@ -409,18 +419,13 @@ public class Daemon {
}
} else {
// mismatch, disallow
if (log != null)
log.append("Action: " + action + " failed because" +
" destination for old name " + poldname +
" does not match new name " + key +
" from " + addressbook.getLocation());
invalid++;
logMismatch(log, action, key, pod, he.getDest(), addressbook);
continue;
}
} else {
if (log != null)
log.append("Action: " + action + " failed, missing required parameters" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
@ -446,11 +451,11 @@ public class Daemon {
if (success)
log.append("Removed: " + poldname +
" as requested" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname +
" as requested" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (published != null) {
@ -462,17 +467,13 @@ public class Daemon {
}
} else if (pod2 != null) {
// mismatch, disallow
if (log != null)
log.append("Action: " + action + " failed because" +
" destination for " + poldname +
" does not match" +
" from " + addressbook.getLocation());
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
}
} else {
if (log != null)
log.append("Action: " + action + " failed, missing required parameters" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
}
continue;
@ -500,11 +501,11 @@ public class Daemon {
if (success)
log.append("Removed: " + poldname +
" as requested" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname +
" as requested" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (published != null) {
@ -516,11 +517,7 @@ public class Daemon {
}
} else if (pod2 != null) {
// mismatch, disallow
if (log != null)
log.append("Action: " + action + " failed because" +
" destination for " + poldname +
" does not match" +
" from " + addressbook.getLocation());
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
}
}
@ -546,11 +543,11 @@ public class Daemon {
if (success)
log.append("Removed: " + rev +
" as requested" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + rev +
" as requested" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (published != null) {
@ -564,7 +561,7 @@ public class Daemon {
} else {
if (log != null)
log.append("Action: " + action + " failed, missing required parameters" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
}
continue;
@ -575,7 +572,7 @@ public class Daemon {
} else {
if (log != null)
log.append("Action: " + action + " unrecognized" +
" from " + addressbook.getLocation());
". From: " + addressbook.getLocation());
invalid++;
continue;
}
@ -602,7 +599,7 @@ public class Daemon {
knownNames.add(key);
nnew++;
} else if (log != null) {
log.append("Bad hostname " + key + " from "
log.append("Bad hostname " + key + ". From: "
+ addressbook.getLocation());
invalid++;
}
@ -612,7 +609,7 @@ public class Daemon {
if (isTextFile)
oldDest = router.lookup(key);
if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
log.append("Conflict for " + key + " from "
log.append("Conflict for " + key + ". From: "
+ addressbook.getLocation()
+ ". Destination in remote address book is "
+ entry.getValue());
@ -645,6 +642,25 @@ public class Daemon {
subscriptions.write();
}
private static void logMismatch(Log log, String action, String name, List<Destination> dests,
String olddest, AddressBook addressbook) {
if (log != null) {
StringBuilder buf = new StringBuilder(16);
final int sz = dests.size();
for (int i = 0; i < sz; i++) {
buf.append(dests.get(i).toBase64().substring(0, 6));
if (i != sz - 1)
buf.append(", ");
}
log.append("Action: " + action + " failed because" +
" destinations for " + name +
" (" + buf + ')' +
" do not include" +
" (" + olddest.substring(0, 6) + ')' +
". From: " + addressbook.getLocation());
}
}
/**
* Run an update, using the Map settings to provide the parameters.
*

View File

@ -19,6 +19,7 @@ import net.i2p.util.OrderedProperties;
import java.io.File;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.Arrays;
import net.i2p.data.Base32;
import net.i2p.data.PrivateKeyFile;
import net.i2p.data.SigningPrivateKey;
@ -398,12 +399,31 @@ class HostTxtEntry {
props.setProperty(sigprop, s.toBase64());
}
/**
* Usage: HostTxtEntry [-i] [-x] [hostname.i2p] [key=val]...
*/
public static void main(String[] args) throws Exception {
int astart = 0;
if (args.length > 0 && args[0].equals("-i"))
astart++;
boolean inner = false;
boolean remove = false;
if (args.length > 0 && args[0].equals("-i")) {
inner = true;
args = Arrays.copyOfRange(args, 1, args.length);
}
if (args.length > 0 && args[0].equals("-x")) {
remove = true;
args = Arrays.copyOfRange(args, 1, args.length);
}
String host;
if (args.length > 0 && args[0].endsWith(".i2p")) {
host = args[0];
args = Arrays.copyOfRange(args, 1, args.length);
} else {
byte[] rand = new byte[5];
RandomSource.getInstance().nextBytes(rand);
host = Base32.encode(rand) + ".i2p";
}
OrderedProperties props = new OrderedProperties();
for (int i = astart; i < args.length; i++) {
for (int i = 0; i < args.length; i++) {
int eq = args[i].indexOf("=");
props.setProperty(args[i].substring(0, eq), args[i].substring(eq + 1));
}
@ -412,28 +432,25 @@ class HostTxtEntry {
File f = new File("tmp-eepPriv.dat");
PrivateKeyFile pkf = new PrivateKeyFile(f);
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
f.delete();
//f.delete();
PrivateKeyFile pkf2;
if (astart != 0) {
if (inner) {
// inner
File f2 = new File("tmp-eepPriv2.dat");
pkf2 = new PrivateKeyFile(f2);
pkf2.createIfAbsent(SigType.DSA_SHA1);
f2.delete();
//f2.delete();
props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64());
} else {
pkf2 = null;
}
byte[] rand = new byte[5];
RandomSource.getInstance().nextBytes(rand);
String host = Base32.encode(rand) + ".i2p";
HostTxtEntry he = new HostTxtEntry(host, pkf.getDestination().toBase64(), props);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
//out.write("Before signing:\n");
//he.write(out);
//out.flush();
SigningPrivateKey priv = pkf.getSigningPrivKey();
if (astart != 0) {
if (inner) {
SigningPrivateKey priv2 = pkf2.getSigningPrivKey();
he.signInner(priv2);
//out.write("After signing inner:\n");
@ -443,7 +460,7 @@ class HostTxtEntry {
//out.write("After signing:\n");
he.write(out);
out.flush();
if (astart > 0 && !he.hasValidInnerSig())
if (inner && !he.hasValidInnerSig())
throw new IllegalStateException("Inner fail 1");
if (!he.hasValidSig())
throw new IllegalStateException("Outer fail 1");
@ -455,25 +472,27 @@ class HostTxtEntry {
String line = sw.toString();
line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2);
HostTxtEntry he2 = new HostTxtEntry(host, pkf.getDestination().toBase64(), line);
if (astart > 0 && !he2.hasValidInnerSig())
if (inner && !he2.hasValidInnerSig())
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");
if (remove) {
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();