forked from I2P_Developers/i2p.i2p
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:
@ -202,40 +202,50 @@ public class Daemon {
|
|||||||
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
|
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
|
||||||
if (polddest != null) {
|
if (polddest != null) {
|
||||||
Destination pod = new Destination(polddest);
|
Destination pod = new Destination(polddest);
|
||||||
// fill in oldDest for .txt naming service
|
List<Destination> pod2 = router.lookupAll(key);
|
||||||
if (isKnown && isTextFile)
|
if (pod2 == null) {
|
||||||
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) {
|
|
||||||
// we didn't know it before, so we'll add it
|
// 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
|
// we knew it before, with the same dest
|
||||||
old++;
|
old++;
|
||||||
continue;
|
continue;
|
||||||
} else if (pod.equals(oldDest)) {
|
} else if (pod2.contains(pod)) {
|
||||||
// checks out, so verify the inner sig
|
// checks out, so verify the inner sig
|
||||||
if (!he.hasValidInnerSig()) {
|
if (!he.hasValidInnerSig()) {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed because" +
|
log.append("Action: " + action + " failed because" +
|
||||||
" inner signature for key " + key +
|
" inner signature for key " + key +
|
||||||
" failed" +
|
" failed" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// TODO Requires NamingService support
|
// TODO Requires NamingService support
|
||||||
// if (isTextFile), do we replace or not? check sigType.isAvailable()
|
// if (isTextFile), do we replace or not? check sigType.isAvailable()
|
||||||
// router.addAltDest(dest)
|
boolean success = router.addDestination(key, dest, props);
|
||||||
if (log != null)
|
if (log != null) {
|
||||||
log.append("Action: " + action + " unimplemented" +
|
if (success)
|
||||||
" from " + addressbook.getLocation());
|
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++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -261,18 +271,14 @@ public class Daemon {
|
|||||||
// checks out, so we'll add the new one
|
// checks out, so we'll add the new one
|
||||||
} else {
|
} else {
|
||||||
// mismatch, disallow
|
// mismatch, disallow
|
||||||
if (log != null)
|
logMismatch(log, action, key, pod, he.getDest(), addressbook);
|
||||||
log.append("Action: " + action + " failed because" +
|
|
||||||
" destination for old name " + poldname +
|
|
||||||
" does not match" +
|
|
||||||
" from " + addressbook.getLocation());
|
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed, missing required parameters" +
|
log.append("Action: " + action + " failed, missing required parameters" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -292,7 +298,7 @@ public class Daemon {
|
|||||||
log.append("Action: " + action + " failed because" +
|
log.append("Action: " + action + " failed because" +
|
||||||
" old name " + poldname +
|
" old name " + poldname +
|
||||||
" is invalid" +
|
" is invalid" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -300,6 +306,7 @@ public class Daemon {
|
|||||||
List<Destination> pod2 = router.lookupAll(poldname);
|
List<Destination> pod2 = router.lookupAll(poldname);
|
||||||
if (pod2 == null) {
|
if (pod2 == null) {
|
||||||
// we didn't have the old name
|
// we didn't have the old name
|
||||||
|
// TODO check inner sig anyway?
|
||||||
} else if (pod2.contains(pod)) {
|
} else if (pod2.contains(pod)) {
|
||||||
// checks out, so verify the inner sig
|
// checks out, so verify the inner sig
|
||||||
if (!he.hasValidInnerSig()) {
|
if (!he.hasValidInnerSig()) {
|
||||||
@ -307,24 +314,20 @@ public class Daemon {
|
|||||||
log.append("Action: " + action + " failed because" +
|
log.append("Action: " + action + " failed because" +
|
||||||
" inner signature for old name " + poldname +
|
" inner signature for old name " + poldname +
|
||||||
" failed" +
|
" failed" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// mismatch, disallow
|
// mismatch, disallow
|
||||||
if (log != null)
|
logMismatch(log, action, key, pod2, polddest, addressbook);
|
||||||
log.append("Action: " + action + " failed because" +
|
|
||||||
" destination for old name " + poldname +
|
|
||||||
" does not match provided" +
|
|
||||||
" from " + addressbook.getLocation());
|
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed, missing required parameters" +
|
log.append("Action: " + action + " failed, missing required parameters" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -335,37 +338,44 @@ public class Daemon {
|
|||||||
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
|
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
|
||||||
if (polddest != null) {
|
if (polddest != null) {
|
||||||
Destination pod = new Destination(polddest);
|
Destination pod = new Destination(polddest);
|
||||||
// fill in oldDest for .txt naming service
|
List<Destination> pod2 = router.lookupAll(key);
|
||||||
if (isKnown && isTextFile)
|
if (pod2 == null) {
|
||||||
oldDest = router.lookup(key);
|
|
||||||
if (!isKnown) {
|
|
||||||
// we didn't have the old name
|
// 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
|
// checks out, so verify the inner sig
|
||||||
if (!he.hasValidInnerSig()) {
|
if (!he.hasValidInnerSig()) {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed because" +
|
log.append("Action: " + action + " failed because" +
|
||||||
" inner signature for key " + key +
|
" inner signature for key " + key +
|
||||||
" failed" +
|
" failed" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
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
|
// TODO set flag to do non-putifabsent for published below
|
||||||
} else {
|
} else {
|
||||||
// mismatch, disallow
|
// mismatch, disallow
|
||||||
if (log != null)
|
logMismatch(log, action, key, pod2, polddest, addressbook);
|
||||||
log.append("Action: " + action + " failed because" +
|
|
||||||
" destination for key " + key +
|
|
||||||
" does not match provided" +
|
|
||||||
" from " + addressbook.getLocation());
|
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed, missing required parameters" +
|
log.append("Action: " + action + " failed, missing required parameters" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -393,11 +403,11 @@ public class Daemon {
|
|||||||
if (success)
|
if (success)
|
||||||
log.append("Removed: " + poldname +
|
log.append("Removed: " + poldname +
|
||||||
" to be replaced with " + key +
|
" to be replaced with " + key +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
else
|
else
|
||||||
log.append("Remove failed for: " + poldname +
|
log.append("Remove failed for: " + poldname +
|
||||||
" to be replaced with " + key +
|
" to be replaced with " + key +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
}
|
}
|
||||||
// now update the published addressbook
|
// now update the published addressbook
|
||||||
if (published != null) {
|
if (published != null) {
|
||||||
@ -409,18 +419,13 @@ public class Daemon {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// mismatch, disallow
|
// mismatch, disallow
|
||||||
if (log != null)
|
logMismatch(log, action, key, pod, he.getDest(), addressbook);
|
||||||
log.append("Action: " + action + " failed because" +
|
|
||||||
" destination for old name " + poldname +
|
|
||||||
" does not match new name " + key +
|
|
||||||
" from " + addressbook.getLocation());
|
|
||||||
invalid++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed, missing required parameters" +
|
log.append("Action: " + action + " failed, missing required parameters" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -446,11 +451,11 @@ public class Daemon {
|
|||||||
if (success)
|
if (success)
|
||||||
log.append("Removed: " + poldname +
|
log.append("Removed: " + poldname +
|
||||||
" as requested" +
|
" as requested" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
else
|
else
|
||||||
log.append("Remove failed for: " + poldname +
|
log.append("Remove failed for: " + poldname +
|
||||||
" as requested" +
|
" as requested" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
}
|
}
|
||||||
// now update the published addressbook
|
// now update the published addressbook
|
||||||
if (published != null) {
|
if (published != null) {
|
||||||
@ -462,17 +467,13 @@ public class Daemon {
|
|||||||
}
|
}
|
||||||
} else if (pod2 != null) {
|
} else if (pod2 != null) {
|
||||||
// mismatch, disallow
|
// mismatch, disallow
|
||||||
if (log != null)
|
logMismatch(log, action, key, pod2, polddest, addressbook);
|
||||||
log.append("Action: " + action + " failed because" +
|
|
||||||
" destination for " + poldname +
|
|
||||||
" does not match" +
|
|
||||||
" from " + addressbook.getLocation());
|
|
||||||
invalid++;
|
invalid++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed, missing required parameters" +
|
log.append("Action: " + action + " failed, missing required parameters" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -500,11 +501,11 @@ public class Daemon {
|
|||||||
if (success)
|
if (success)
|
||||||
log.append("Removed: " + poldname +
|
log.append("Removed: " + poldname +
|
||||||
" as requested" +
|
" as requested" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
else
|
else
|
||||||
log.append("Remove failed for: " + poldname +
|
log.append("Remove failed for: " + poldname +
|
||||||
" as requested" +
|
" as requested" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
}
|
}
|
||||||
// now update the published addressbook
|
// now update the published addressbook
|
||||||
if (published != null) {
|
if (published != null) {
|
||||||
@ -516,11 +517,7 @@ public class Daemon {
|
|||||||
}
|
}
|
||||||
} else if (pod2 != null) {
|
} else if (pod2 != null) {
|
||||||
// mismatch, disallow
|
// mismatch, disallow
|
||||||
if (log != null)
|
logMismatch(log, action, key, pod2, polddest, addressbook);
|
||||||
log.append("Action: " + action + " failed because" +
|
|
||||||
" destination for " + poldname +
|
|
||||||
" does not match" +
|
|
||||||
" from " + addressbook.getLocation());
|
|
||||||
invalid++;
|
invalid++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -546,11 +543,11 @@ public class Daemon {
|
|||||||
if (success)
|
if (success)
|
||||||
log.append("Removed: " + rev +
|
log.append("Removed: " + rev +
|
||||||
" as requested" +
|
" as requested" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
else
|
else
|
||||||
log.append("Remove failed for: " + rev +
|
log.append("Remove failed for: " + rev +
|
||||||
" as requested" +
|
" as requested" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
}
|
}
|
||||||
// now update the published addressbook
|
// now update the published addressbook
|
||||||
if (published != null) {
|
if (published != null) {
|
||||||
@ -564,7 +561,7 @@ public class Daemon {
|
|||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " failed, missing required parameters" +
|
log.append("Action: " + action + " failed, missing required parameters" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -575,7 +572,7 @@ public class Daemon {
|
|||||||
} else {
|
} else {
|
||||||
if (log != null)
|
if (log != null)
|
||||||
log.append("Action: " + action + " unrecognized" +
|
log.append("Action: " + action + " unrecognized" +
|
||||||
" from " + addressbook.getLocation());
|
". From: " + addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -602,7 +599,7 @@ public class Daemon {
|
|||||||
knownNames.add(key);
|
knownNames.add(key);
|
||||||
nnew++;
|
nnew++;
|
||||||
} else if (log != null) {
|
} else if (log != null) {
|
||||||
log.append("Bad hostname " + key + " from "
|
log.append("Bad hostname " + key + ". From: "
|
||||||
+ addressbook.getLocation());
|
+ addressbook.getLocation());
|
||||||
invalid++;
|
invalid++;
|
||||||
}
|
}
|
||||||
@ -612,7 +609,7 @@ public class Daemon {
|
|||||||
if (isTextFile)
|
if (isTextFile)
|
||||||
oldDest = router.lookup(key);
|
oldDest = router.lookup(key);
|
||||||
if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
|
if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
|
||||||
log.append("Conflict for " + key + " from "
|
log.append("Conflict for " + key + ". From: "
|
||||||
+ addressbook.getLocation()
|
+ addressbook.getLocation()
|
||||||
+ ". Destination in remote address book is "
|
+ ". Destination in remote address book is "
|
||||||
+ entry.getValue());
|
+ entry.getValue());
|
||||||
@ -645,6 +642,25 @@ public class Daemon {
|
|||||||
subscriptions.write();
|
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.
|
* Run an update, using the Map settings to provide the parameters.
|
||||||
*
|
*
|
||||||
|
@ -19,6 +19,7 @@ import net.i2p.util.OrderedProperties;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.util.Arrays;
|
||||||
import net.i2p.data.Base32;
|
import net.i2p.data.Base32;
|
||||||
import net.i2p.data.PrivateKeyFile;
|
import net.i2p.data.PrivateKeyFile;
|
||||||
import net.i2p.data.SigningPrivateKey;
|
import net.i2p.data.SigningPrivateKey;
|
||||||
@ -398,12 +399,31 @@ class HostTxtEntry {
|
|||||||
props.setProperty(sigprop, s.toBase64());
|
props.setProperty(sigprop, s.toBase64());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usage: HostTxtEntry [-i] [-x] [hostname.i2p] [key=val]...
|
||||||
|
*/
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
int astart = 0;
|
boolean inner = false;
|
||||||
if (args.length > 0 && args[0].equals("-i"))
|
boolean remove = false;
|
||||||
astart++;
|
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();
|
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("=");
|
int eq = args[i].indexOf("=");
|
||||||
props.setProperty(args[i].substring(0, eq), args[i].substring(eq + 1));
|
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");
|
File f = new File("tmp-eepPriv.dat");
|
||||||
PrivateKeyFile pkf = new PrivateKeyFile(f);
|
PrivateKeyFile pkf = new PrivateKeyFile(f);
|
||||||
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
|
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
|
||||||
f.delete();
|
//f.delete();
|
||||||
PrivateKeyFile pkf2;
|
PrivateKeyFile pkf2;
|
||||||
if (astart != 0) {
|
if (inner) {
|
||||||
// inner
|
// inner
|
||||||
File f2 = new File("tmp-eepPriv2.dat");
|
File f2 = new File("tmp-eepPriv2.dat");
|
||||||
pkf2 = new PrivateKeyFile(f2);
|
pkf2 = new PrivateKeyFile(f2);
|
||||||
pkf2.createIfAbsent(SigType.DSA_SHA1);
|
pkf2.createIfAbsent(SigType.DSA_SHA1);
|
||||||
f2.delete();
|
//f2.delete();
|
||||||
props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64());
|
props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64());
|
||||||
} else {
|
} else {
|
||||||
pkf2 = null;
|
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);
|
HostTxtEntry he = new HostTxtEntry(host, pkf.getDestination().toBase64(), props);
|
||||||
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
|
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
|
||||||
//out.write("Before signing:\n");
|
//out.write("Before signing:\n");
|
||||||
//he.write(out);
|
//he.write(out);
|
||||||
//out.flush();
|
//out.flush();
|
||||||
SigningPrivateKey priv = pkf.getSigningPrivKey();
|
SigningPrivateKey priv = pkf.getSigningPrivKey();
|
||||||
if (astart != 0) {
|
if (inner) {
|
||||||
SigningPrivateKey priv2 = pkf2.getSigningPrivKey();
|
SigningPrivateKey priv2 = pkf2.getSigningPrivKey();
|
||||||
he.signInner(priv2);
|
he.signInner(priv2);
|
||||||
//out.write("After signing inner:\n");
|
//out.write("After signing inner:\n");
|
||||||
@ -443,7 +460,7 @@ class HostTxtEntry {
|
|||||||
//out.write("After signing:\n");
|
//out.write("After signing:\n");
|
||||||
he.write(out);
|
he.write(out);
|
||||||
out.flush();
|
out.flush();
|
||||||
if (astart > 0 && !he.hasValidInnerSig())
|
if (inner && !he.hasValidInnerSig())
|
||||||
throw new IllegalStateException("Inner fail 1");
|
throw new IllegalStateException("Inner fail 1");
|
||||||
if (!he.hasValidSig())
|
if (!he.hasValidSig())
|
||||||
throw new IllegalStateException("Outer fail 1");
|
throw new IllegalStateException("Outer fail 1");
|
||||||
@ -455,12 +472,13 @@ class HostTxtEntry {
|
|||||||
String line = sw.toString();
|
String line = sw.toString();
|
||||||
line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2);
|
line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2);
|
||||||
HostTxtEntry he2 = new HostTxtEntry(host, pkf.getDestination().toBase64(), line);
|
HostTxtEntry he2 = new HostTxtEntry(host, pkf.getDestination().toBase64(), line);
|
||||||
if (astart > 0 && !he2.hasValidInnerSig())
|
if (inner && !he2.hasValidInnerSig())
|
||||||
throw new IllegalStateException("Inner fail 2");
|
throw new IllegalStateException("Inner fail 2");
|
||||||
if (!he2.hasValidSig())
|
if (!he2.hasValidSig())
|
||||||
throw new IllegalStateException("Outer fail 2");
|
throw new IllegalStateException("Outer fail 2");
|
||||||
|
|
||||||
// 'remove' tests (corrupts earlier sigs)
|
// 'remove' tests (corrupts earlier sigs)
|
||||||
|
if (remove) {
|
||||||
he.getProps().remove(PROP_SIG);
|
he.getProps().remove(PROP_SIG);
|
||||||
he.signRemove(priv);
|
he.signRemove(priv);
|
||||||
//out.write("Remove entry:\n");
|
//out.write("Remove entry:\n");
|
||||||
@ -474,6 +492,7 @@ class HostTxtEntry {
|
|||||||
HostTxtEntry he3 = new HostTxtEntry(line);
|
HostTxtEntry he3 = new HostTxtEntry(line);
|
||||||
if (!he3.hasValidRemoveSig())
|
if (!he3.hasValidRemoveSig())
|
||||||
throw new IllegalStateException("Remove verify fail");
|
throw new IllegalStateException("Remove verify fail");
|
||||||
|
}
|
||||||
|
|
||||||
//out.write("Test passed\n");
|
//out.write("Test passed\n");
|
||||||
//out.flush();
|
//out.flush();
|
||||||
|
@ -10,6 +10,7 @@ package net.i2p.client.naming;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
@ -135,6 +136,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
|
|
||||||
private static final String DUMMY = "";
|
private static final String DUMMY = "";
|
||||||
private static final int NEGATIVE_CACHE_SIZE = 32;
|
private static final int NEGATIVE_CACHE_SIZE = 32;
|
||||||
|
private static final int MAX_VALUE_LENGTH = 4096;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the database at hostsdb.blockfile or creates a new
|
* Opens the database at hostsdb.blockfile or creates a new
|
||||||
@ -852,18 +854,17 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
try {
|
try {
|
||||||
DestEntry de = getEntry(list, key);
|
DestEntry de = getEntry(list, key);
|
||||||
if (de != null) {
|
if (de != null) {
|
||||||
int sz = de.destList.size();
|
|
||||||
// if any are invalid, assume they all are
|
|
||||||
boolean invalid = false;
|
|
||||||
for (int i = 0; i < sz; i++) {
|
|
||||||
if (!validate(key, de, listname))
|
if (!validate(key, de, listname))
|
||||||
invalid = true;
|
|
||||||
}
|
|
||||||
if (invalid)
|
|
||||||
continue;
|
continue;
|
||||||
|
if (de.destList != null) {
|
||||||
rv = de.destList;
|
rv = de.destList;
|
||||||
if (storedOptions != null)
|
if (storedOptions != null)
|
||||||
storedOptions.addAll(de.propsList);
|
storedOptions.addAll(de.propsList);
|
||||||
|
} else {
|
||||||
|
rv = Collections.singletonList(de.dest);
|
||||||
|
if (storedOptions != null)
|
||||||
|
storedOptions.add(de.props);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -1491,10 +1492,10 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
// For now, non-DSA at the front, DSA at the end
|
// For now, non-DSA at the front, DSA at the end
|
||||||
SigType type = d.getSigningPublicKey().getType();
|
SigType type = d.getSigningPublicKey().getType();
|
||||||
if (type != SigType.DSA_SHA1 && type.isAvailable()) {
|
if (type != SigType.DSA_SHA1 && type.isAvailable()) {
|
||||||
dests.add(0, d);
|
newDests.add(0, d);
|
||||||
storedOptions.add(0, options);
|
storedOptions.add(0, options);
|
||||||
} else {
|
} else {
|
||||||
dests.add(d);
|
newDests.add(d);
|
||||||
storedOptions.add(options);
|
storedOptions.add(options);
|
||||||
}
|
}
|
||||||
return put(hostname, newDests, storedOptions, false);
|
return put(hostname, newDests, storedOptions, false);
|
||||||
@ -1562,6 +1563,12 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
de != null &&
|
de != null &&
|
||||||
de.dest != null &&
|
de.dest != null &&
|
||||||
de.dest.getPublicKey() != null;
|
de.dest.getPublicKey() != null;
|
||||||
|
if (_isVersion4 && rv && de.destList != null) {
|
||||||
|
// additional checks for multi-dest
|
||||||
|
rv = de.propsList != null &&
|
||||||
|
de.destList.size() == de.propsList.size() &&
|
||||||
|
!de.destList.contains(null);
|
||||||
|
}
|
||||||
if ((!rv) && (!_readOnly))
|
if ((!rv) && (!_readOnly))
|
||||||
_invalid.add(new InvalidEntry(key, listname));
|
_invalid.add(new InvalidEntry(key, listname));
|
||||||
return rv;
|
return rv;
|
||||||
@ -1706,13 +1713,26 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
* and is serialized in that order.
|
* and is serialized in that order.
|
||||||
*/
|
*/
|
||||||
private static class DestEntry {
|
private static class DestEntry {
|
||||||
/** may be null */
|
/** May be null.
|
||||||
|
* If more than one dest, contains the first props.
|
||||||
|
*/
|
||||||
public Properties props;
|
public Properties props;
|
||||||
/** may not be null */
|
|
||||||
|
/** May not be null.
|
||||||
|
* If more than one dest, contains the first dest.
|
||||||
|
*/
|
||||||
public Destination dest;
|
public Destination dest;
|
||||||
/** may be null - v4 only - same size as destList - may contain null entries */
|
|
||||||
|
/** May be null - v4 only - same size as destList - may contain null entries
|
||||||
|
* Only non-null if more than one dest.
|
||||||
|
* First entry always equal to props.
|
||||||
|
*/
|
||||||
public List<Properties> propsList;
|
public List<Properties> propsList;
|
||||||
/** may be null - v4 only - same size as propsList */
|
|
||||||
|
/** May be null - v4 only - same size as propsList
|
||||||
|
* Only non-null if more than one dest.
|
||||||
|
* First entry always equal to dest.
|
||||||
|
*/
|
||||||
public List<Destination> destList;
|
public List<Destination> destList;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1796,7 +1816,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
d = de.destList.get(i);
|
d = de.destList.get(i);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
DataHelper.writeProperties(baos, p, true, false);
|
writeProperties(baos, p);
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
logError("DB Write Fail - properties too big?", dfe);
|
logError("DB Write Fail - properties too big?", dfe);
|
||||||
baos.write(new byte[2]);
|
baos.write(new byte[2]);
|
||||||
@ -1819,7 +1839,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
int sz = bais.read() & 0xff;
|
int sz = bais.read() & 0xff;
|
||||||
if (sz <= 0)
|
if (sz <= 0)
|
||||||
throw new DataFormatException("bad dest count " + sz);
|
throw new DataFormatException("bad dest count " + sz);
|
||||||
rv.props = DataHelper.readProperties(bais);
|
rv.props = readProperties(bais);
|
||||||
rv.dest = Destination.create(bais);
|
rv.dest = Destination.create(bais);
|
||||||
if (sz > 1) {
|
if (sz > 1) {
|
||||||
rv.propsList = new ArrayList<Properties>(sz);
|
rv.propsList = new ArrayList<Properties>(sz);
|
||||||
@ -1827,7 +1847,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
rv.propsList.add(rv.props);
|
rv.propsList.add(rv.props);
|
||||||
rv.destList.add(rv.dest);
|
rv.destList.add(rv.dest);
|
||||||
for (int i = 1; i < sz; i++) {
|
for (int i = 1; i < sz; i++) {
|
||||||
rv.propsList.add(DataHelper.readProperties(bais));
|
rv.propsList.add(readProperties(bais));
|
||||||
rv.destList.add(Destination.create(bais));
|
rv.destList.add(Destination.create(bais));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1842,6 +1862,132 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as DataHelper.writeProperties, UTF-8, unsorted,
|
||||||
|
* except that values may up to 4K bytes.
|
||||||
|
*
|
||||||
|
* @param props source may be null
|
||||||
|
* @throws DataFormatException if any key string is over 255 bytes long,
|
||||||
|
* if any value string is over 4096 bytes long, or if the total length
|
||||||
|
* (not including the two length bytes) is greater than 65535 bytes.
|
||||||
|
* @since 0.9.26
|
||||||
|
*/
|
||||||
|
private static void writeProperties(ByteArrayOutputStream rawStream, Properties p)
|
||||||
|
throws DataFormatException, IOException {
|
||||||
|
if (p != null && !p.isEmpty()) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(p.size() * 32);
|
||||||
|
for (Map.Entry<Object, Object> entry : p.entrySet()) {
|
||||||
|
String key = (String) entry.getKey();
|
||||||
|
String val = (String) entry.getValue();
|
||||||
|
DataHelper.writeStringUTF8(baos, key);
|
||||||
|
baos.write('=');
|
||||||
|
writeLongStringUTF8(baos, val);
|
||||||
|
baos.write(';');
|
||||||
|
}
|
||||||
|
if (baos.size() > 65535)
|
||||||
|
throw new DataFormatException("Properties too big (65535 max): " + baos.size());
|
||||||
|
byte propBytes[] = baos.toByteArray();
|
||||||
|
DataHelper.writeLong(rawStream, 2, propBytes.length);
|
||||||
|
rawStream.write(propBytes);
|
||||||
|
} else {
|
||||||
|
DataHelper.writeLong(rawStream, 2, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as DataHelper.readProperties, UTF-8, unsorted,
|
||||||
|
* except that values may up to 4K bytes.
|
||||||
|
*
|
||||||
|
* Throws DataFormatException on duplicate key
|
||||||
|
*
|
||||||
|
* @param rawStream stream to read the mapping from
|
||||||
|
* @throws DataFormatException if the format is invalid
|
||||||
|
* @throws IOException if there is a problem reading the data
|
||||||
|
* @return a Properties
|
||||||
|
* @since 0.9.26
|
||||||
|
*/
|
||||||
|
public static Properties readProperties(ByteArrayInputStream in)
|
||||||
|
throws DataFormatException, IOException {
|
||||||
|
Properties props = new Properties();
|
||||||
|
int size = (int) DataHelper.readLong(in, 2);
|
||||||
|
// this doesn't prevent reading past the end on corruption
|
||||||
|
int ignore = in.available() - size;
|
||||||
|
while (in.available() > ignore) {
|
||||||
|
String key = DataHelper.readString(in);
|
||||||
|
int b = in.read();
|
||||||
|
if (b != '=')
|
||||||
|
throw new DataFormatException("Bad key " + b);
|
||||||
|
String val = readLongString(in);
|
||||||
|
b = in.read();
|
||||||
|
if (b != ';')
|
||||||
|
throw new DataFormatException("Bad value");
|
||||||
|
Object old = props.put(key, val);
|
||||||
|
if (old != null)
|
||||||
|
throw new DataFormatException("Duplicate key " + key);
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as DataHelper.writeStringUTF8, except that
|
||||||
|
* strings up to 4K bytes are allowed.
|
||||||
|
* Format is: one-byte length + data, or 0xff + two-byte length + data
|
||||||
|
*
|
||||||
|
* @param out stream to write string
|
||||||
|
* @param string to write out: null strings are valid, but strings of excess length will
|
||||||
|
* cause a DataFormatException to be thrown
|
||||||
|
* @throws DataFormatException if the string is not valid
|
||||||
|
* @throws IOException if there is an IO error writing the string
|
||||||
|
*/
|
||||||
|
private static void writeLongStringUTF8(ByteArrayOutputStream out, String string)
|
||||||
|
throws DataFormatException, IOException {
|
||||||
|
if (string == null) {
|
||||||
|
out.write(0);
|
||||||
|
} else {
|
||||||
|
byte[] raw = string.getBytes("UTF-8");
|
||||||
|
int len = raw.length;
|
||||||
|
if (len >= 255) {
|
||||||
|
if (len > MAX_VALUE_LENGTH)
|
||||||
|
throw new DataFormatException(MAX_VALUE_LENGTH + " max, but this is "
|
||||||
|
+ len + " [" + string + "]");
|
||||||
|
out.write(0xff);
|
||||||
|
DataHelper.writeLong(out, 2, len);
|
||||||
|
} else {
|
||||||
|
out.write(len);
|
||||||
|
}
|
||||||
|
out.write(raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as DataHelper.readString, except that
|
||||||
|
* strings up to 4K bytes are allowed.
|
||||||
|
* Format is: one-byte length + data, or 0xff + two-byte length + data
|
||||||
|
*
|
||||||
|
* @param in stream to read from
|
||||||
|
* @throws DataFormatException if the stream doesn't contain a validly formatted string
|
||||||
|
* @throws EOFException if there aren't enough bytes to read the string
|
||||||
|
* @throws IOException if there is an IO error reading the string
|
||||||
|
* @return UTF-8 string
|
||||||
|
*/
|
||||||
|
private static String readLongString(ByteArrayInputStream in) throws DataFormatException, IOException {
|
||||||
|
int size = in.read();
|
||||||
|
if (size < 0)
|
||||||
|
throw new EOFException("EOF reading string");
|
||||||
|
if (size == 0xff) {
|
||||||
|
size = (int) DataHelper.readLong(in, 2);
|
||||||
|
if (size > MAX_VALUE_LENGTH)
|
||||||
|
throw new DataFormatException(MAX_VALUE_LENGTH + " max, but this is " + size);
|
||||||
|
}
|
||||||
|
if (size == 0)
|
||||||
|
return "";
|
||||||
|
byte raw[] = new byte[size];
|
||||||
|
int read = DataHelper.read(in, raw);
|
||||||
|
if (read != size)
|
||||||
|
throw new EOFException("EOF reading string");
|
||||||
|
return new String(raw, "UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to store entries that need deleting
|
* Used to store entries that need deleting
|
||||||
*/
|
*/
|
||||||
|
@ -56,8 +56,6 @@ import net.i2p.util.Translate;
|
|||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class DataHelper {
|
public class DataHelper {
|
||||||
private static final byte[] EQUAL_BYTES = getUTF8("=");
|
|
||||||
private static final byte[] SEMICOLON_BYTES = getUTF8(";");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of String to itself to cache common
|
* Map of String to itself to cache common
|
||||||
@ -148,22 +146,18 @@ public class DataHelper {
|
|||||||
int read = read(rawStream, data);
|
int read = read(rawStream, data);
|
||||||
if (read != size) throw new DataFormatException("Not enough data to read the properties, expected " + size + " but got " + read);
|
if (read != size) throw new DataFormatException("Not enough data to read the properties, expected " + size + " but got " + read);
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(data);
|
ByteArrayInputStream in = new ByteArrayInputStream(data);
|
||||||
byte eqBuf[] = new byte[EQUAL_BYTES.length];
|
|
||||||
byte semiBuf[] = new byte[SEMICOLON_BYTES.length];
|
|
||||||
while (in.available() > 0) {
|
while (in.available() > 0) {
|
||||||
String key = readString(in);
|
String key = readString(in);
|
||||||
String cached = _propertiesKeyCache.get(key);
|
String cached = _propertiesKeyCache.get(key);
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
key = cached;
|
key = cached;
|
||||||
read = read(in, eqBuf);
|
int b = in.read();
|
||||||
if ((read != eqBuf.length) || (!eq(eqBuf, EQUAL_BYTES))) {
|
if (b != '=')
|
||||||
throw new DataFormatException("Bad key");
|
throw new DataFormatException("Bad key");
|
||||||
}
|
|
||||||
String val = readString(in);
|
String val = readString(in);
|
||||||
read = read(in, semiBuf);
|
b = in.read();
|
||||||
if ((read != semiBuf.length) || (!eq(semiBuf, SEMICOLON_BYTES))) {
|
if (b != ';')
|
||||||
throw new DataFormatException("Bad value");
|
throw new DataFormatException("Bad value");
|
||||||
}
|
|
||||||
Object old = props.put(key, val);
|
Object old = props.put(key, val);
|
||||||
if (old != null)
|
if (old != null)
|
||||||
throw new DataFormatException("Duplicate key " + key);
|
throw new DataFormatException("Duplicate key " + key);
|
||||||
@ -182,7 +176,7 @@ public class DataHelper {
|
|||||||
* Properties from the defaults table of props (if any) are not written out by this method.
|
* Properties from the defaults table of props (if any) are not written out by this method.
|
||||||
*
|
*
|
||||||
* @param rawStream stream to write to
|
* @param rawStream stream to write to
|
||||||
* @param props properties to write out
|
* @param props properties to write out, may be null
|
||||||
* @throws DataFormatException if there is not enough valid data to write out,
|
* @throws DataFormatException if there is not enough valid data to write out,
|
||||||
* or a length limit is exceeded
|
* or a length limit is exceeded
|
||||||
* @throws IOException if there is an IO error writing out the data
|
* @throws IOException if there is an IO error writing out the data
|
||||||
@ -239,7 +233,7 @@ public class DataHelper {
|
|||||||
*/
|
*/
|
||||||
public static void writeProperties(OutputStream rawStream, Properties props, boolean utf8, boolean sort)
|
public static void writeProperties(OutputStream rawStream, Properties props, boolean utf8, boolean sort)
|
||||||
throws DataFormatException, IOException {
|
throws DataFormatException, IOException {
|
||||||
if (props != null) {
|
if (props != null && !props.isEmpty()) {
|
||||||
Properties p;
|
Properties p;
|
||||||
if (sort) {
|
if (sort) {
|
||||||
p = new OrderedProperties();
|
p = new OrderedProperties();
|
||||||
@ -255,12 +249,12 @@ public class DataHelper {
|
|||||||
writeStringUTF8(baos, key);
|
writeStringUTF8(baos, key);
|
||||||
else
|
else
|
||||||
writeString(baos, key);
|
writeString(baos, key);
|
||||||
baos.write(EQUAL_BYTES);
|
baos.write('=');
|
||||||
if (utf8)
|
if (utf8)
|
||||||
writeStringUTF8(baos, val);
|
writeStringUTF8(baos, val);
|
||||||
else
|
else
|
||||||
writeString(baos, val);
|
writeString(baos, val);
|
||||||
baos.write(SEMICOLON_BYTES);
|
baos.write(';');
|
||||||
}
|
}
|
||||||
if (baos.size() > 65535)
|
if (baos.size() > 65535)
|
||||||
throw new DataFormatException("Properties too big (65535 max): " + baos.size());
|
throw new DataFormatException("Properties too big (65535 max): " + baos.size());
|
||||||
@ -301,9 +295,9 @@ public class DataHelper {
|
|||||||
String key = (String) entry.getKey();
|
String key = (String) entry.getKey();
|
||||||
String val = (String) entry.getValue();
|
String val = (String) entry.getValue();
|
||||||
writeStringUTF8(baos, key);
|
writeStringUTF8(baos, key);
|
||||||
baos.write(EQUAL_BYTES);
|
baos.write('=');
|
||||||
writeStringUTF8(baos, val);
|
writeStringUTF8(baos, val);
|
||||||
baos.write(SEMICOLON_BYTES);
|
baos.write(';');
|
||||||
}
|
}
|
||||||
if (baos.size() > 65535)
|
if (baos.size() > 65535)
|
||||||
throw new DataFormatException("Properties too big (65535 max): " + baos.size());
|
throw new DataFormatException("Properties too big (65535 max): " + baos.size());
|
||||||
@ -335,8 +329,6 @@ public class DataHelper {
|
|||||||
int size = (int)fromLong(source, offset, 2);
|
int size = (int)fromLong(source, offset, 2);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(source, offset, size);
|
ByteArrayInputStream in = new ByteArrayInputStream(source, offset, size);
|
||||||
byte eqBuf[] = new byte[EQUAL_BYTES.length];
|
|
||||||
byte semiBuf[] = new byte[SEMICOLON_BYTES.length];
|
|
||||||
while (in.available() > 0) {
|
while (in.available() > 0) {
|
||||||
String key;
|
String key;
|
||||||
try {
|
try {
|
||||||
@ -344,20 +336,18 @@ public class DataHelper {
|
|||||||
String cached = _propertiesKeyCache.get(key);
|
String cached = _propertiesKeyCache.get(key);
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
key = cached;
|
key = cached;
|
||||||
int read = read(in, eqBuf);
|
int b = in.read();
|
||||||
if ((read != eqBuf.length) || (!eq(eqBuf, EQUAL_BYTES))) {
|
if (b != '=')
|
||||||
throw new DataFormatException("Bad key");
|
throw new DataFormatException("Bad key");
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new DataFormatException("Bad key", ioe);
|
throw new DataFormatException("Bad key", ioe);
|
||||||
}
|
}
|
||||||
String val;
|
String val;
|
||||||
try {
|
try {
|
||||||
val = readString(in);
|
val = readString(in);
|
||||||
int read = read(in, semiBuf);
|
int b = in.read();
|
||||||
if ((read != semiBuf.length) || (!eq(semiBuf, SEMICOLON_BYTES))) {
|
if (b != ';')
|
||||||
throw new DataFormatException("Bad value");
|
throw new DataFormatException("Bad value");
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new DataFormatException("Bad value", ioe);
|
throw new DataFormatException("Bad value", ioe);
|
||||||
}
|
}
|
||||||
@ -910,8 +900,9 @@ public class DataHelper {
|
|||||||
* cause a DataFormatException to be thrown
|
* cause a DataFormatException to be thrown
|
||||||
* @throws DataFormatException if the string is not valid
|
* @throws DataFormatException if the string is not valid
|
||||||
* @throws IOException if there is an IO error writing the string
|
* @throws IOException if there is an IO error writing the string
|
||||||
|
* @since public since 0.9.26
|
||||||
*/
|
*/
|
||||||
private static void writeStringUTF8(OutputStream out, String string)
|
public static void writeStringUTF8(OutputStream out, String string)
|
||||||
throws DataFormatException, IOException {
|
throws DataFormatException, IOException {
|
||||||
if (string == null) {
|
if (string == null) {
|
||||||
out.write((byte) 0);
|
out.write((byte) 0);
|
||||||
@ -936,6 +927,7 @@ public class DataHelper {
|
|||||||
* @return boolean value, or null
|
* @return boolean value, or null
|
||||||
* @deprecated unused
|
* @deprecated unused
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Boolean readBoolean(InputStream in) throws DataFormatException, IOException {
|
public static Boolean readBoolean(InputStream in) throws DataFormatException, IOException {
|
||||||
int val = in.read();
|
int val = in.read();
|
||||||
switch (val) {
|
switch (val) {
|
||||||
|
Reference in New Issue
Block a user