From 4f262f61409d33e1f008dd1fdd6d7010dc92302e Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Thu, 21 Apr 2016 14:37:38 +0000 Subject: [PATCH] Addressbook: Use new NamingService API methods in action handling - Refactor HostTxtEntry to consolidate properties writing - More HostTxtEntry tests - Start of 'remove' entry handling Blockfile: Cleanup unused code - Add Iterable interface to SkipList --- .../java/src/net/i2p/addressbook/Daemon.java | 46 ++-- .../src/net/i2p/addressbook/HostTxtEntry.java | 236 +++++++++--------- .../net/i2p/addressbook/HostTxtParser.java | 5 +- .../metanotion/io/block/index/BSkipList.java | 2 + .../src/net/metanotion/io/data/LongBytes.java | 59 ----- .../metanotion/util/skiplist/SkipList.java | 6 +- 6 files changed, 158 insertions(+), 196 deletions(-) delete mode 100644 core/java/src/net/metanotion/io/data/LongBytes.java diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java index aaa2ea9a58..297e6c0e1f 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java @@ -254,10 +254,10 @@ public class Daemon { } String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME); if (poldname != null) { - Destination pod = router.lookup(poldname); + List<Destination> pod = router.lookupAll(poldname); if (pod == null) { // we didn't have the old one, so we'll add the new one - } else if (pod.equals(dest)) { + } else if (pod.contains(dest)) { // checks out, so we'll add the new one } else { // mismatch, disallow @@ -297,10 +297,10 @@ public class Daemon { continue; } Destination pod = new Destination(polddest); - Destination pod2 = router.lookup(poldname); + List<Destination> pod2 = router.lookupAll(poldname); if (pod2 == null) { // we didn't have the old name - } else if (pod.equals(pod2)) { + } else if (pod2.contains(pod)) { // checks out, so verify the inner sig if (!he.hasValidInnerSig()) { if (log != null) @@ -330,6 +330,8 @@ public class Daemon { } } else if (action.equals(HostTxtEntry.ACTION_CHANGEDEST)) { // change destination on an existing entry + // This removes all previous destinations under that hostname, + // is this what we want? String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST); if (polddest != null) { Destination pod = new Destination(polddest); @@ -369,20 +371,22 @@ public class Daemon { } } else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) { // Delete old name, replace with new + // This removes all previous destinations under that hostname, + // is this what we want? if (isKnown) { old++; continue; } String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME); if (poldname != null) { - Destination pod = router.lookup(poldname); + List<Destination> pod = router.lookupAll(poldname); if (pod == null) { // we didn't have the old name - } else if (pod.equals(dest)) { + } else if (pod.contains(dest)) { // checks out, so we'll delete it if (knownNames != null) knownNames.remove(poldname); - boolean success = router.remove(poldname); + boolean success = router.remove(poldname, dest); if (success) deleted++; if (log != null) { @@ -399,7 +403,7 @@ public class Daemon { if (published != null) { if (publishedNS == null) publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); - success = publishedNS.remove(poldname); + success = publishedNS.remove(poldname, dest); if (log != null && !success) log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname); } @@ -431,11 +435,11 @@ public class Daemon { String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME); if (polddest != null && poldname != null) { Destination pod = new Destination(polddest); - Destination pod2 = router.lookup(poldname); - if (pod.equals(pod2)) { - if (knownNames != null) + List<Destination> pod2 = router.lookupAll(poldname); + if (pod2 != null && pod2.contains(pod)) { + if (knownNames != null && pod2.size() == 1) knownNames.remove(poldname); - boolean success = router.remove(poldname); + boolean success = router.remove(poldname, pod); if (success) deleted++; if (log != null) { @@ -452,7 +456,7 @@ public class Daemon { if (published != null) { if (publishedNS == null) publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); - success = publishedNS.remove(poldname); + success = publishedNS.remove(poldname, pod); if (log != null && !success) log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname); } @@ -485,11 +489,11 @@ public class Daemon { Destination pod = new Destination(polddest); String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME); if (poldname != null) { - Destination pod2 = router.lookup(poldname); - if (pod.equals(pod2)) { + List<Destination> pod2 = router.lookupAll(poldname); + if (pod2 != null && pod2.contains(pod)) { if (knownNames != null) knownNames.remove(poldname); - boolean success = router.remove(poldname); + boolean success = router.remove(poldname, pod); if (success) deleted++; if (log != null) { @@ -506,7 +510,7 @@ public class Daemon { if (published != null) { if (publishedNS == null) publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); - success = publishedNS.remove(poldname); + success = publishedNS.remove(poldname, pod); if (log != null && !success) log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname); } @@ -530,12 +534,12 @@ public class Daemon { break; rev2 = rev; // forward check in case hash collision or something - Destination fwd = router.lookup(rev); - if (!pod.equals(fwd)) + List<Destination> fwd = router.lookupAll(rev); + if (!fwd.contains(pod)) break; // can't go around again, fail if (knownNames != null) knownNames.remove(rev); - boolean success = router.remove(rev); + boolean success = router.remove(rev, pod); if (success) deleted++; if (log != null) { @@ -552,7 +556,7 @@ public class Daemon { if (published != null) { if (publishedNS == null) publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); - success = publishedNS.remove(rev); + success = publishedNS.remove(rev, pod); if (log != null && !success) log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + rev); } diff --git a/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java b/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java index f1934cc3c7..9f0e0a37d6 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/HostTxtEntry.java @@ -2,6 +2,8 @@ package net.i2p.addressbook; import java.io.BufferedWriter; import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; import java.util.Map; import net.i2p.crypto.DSAEngine; @@ -17,8 +19,10 @@ import net.i2p.util.OrderedProperties; import java.io.File; import java.io.OutputStreamWriter; import java.io.StringWriter; +import net.i2p.data.Base32; import net.i2p.data.PrivateKeyFile; import net.i2p.data.SigningPrivateKey; +import net.i2p.util.RandomSource; /** @@ -97,7 +101,7 @@ class HostTxtEntry { * @param line part after the #! * @throws IllegalArgumentException on dup key and other errors */ - private OrderedProperties parseProps(String line) throws IllegalArgumentException { + private static OrderedProperties parseProps(String line) throws IllegalArgumentException { line = line.trim(); OrderedProperties rv = new OrderedProperties(); String[] entries = DataHelper.split(line, "#"); @@ -115,27 +119,58 @@ class HostTxtEntry { return rv; } + /** + * Write as a standard line name=dest[#!k1=v1#k2=v2...] + * Includes newline. + */ public void write(BufferedWriter out) throws IOException { out.write(name); out.write(KV_SEPARATOR); out.write(dest); - if (props != null && props.size() > 0) { - boolean started = false; - for (Map.Entry<Object, Object> e : props.entrySet()) { - if (started) { - out.write(PROP_SEPARATOR); - } else { - started = true; - out.write(PROPS_SEPARATOR); - } - String k = (String) e.getKey(); - String v = (String) e.getValue(); - out.write(k); - out.write(KV_SEPARATOR); - out.write(v); + writeProps(out, false, false); + out.newLine(); + } + + /** + * Write as a "remove" line #!olddest=dest#oldname=name#k1=v1#k2=v2...] + * 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); + writeProps(out, false, false); + out.newLine(); + props.remove(PROP_OLDNAME); + props.remove(PROP_OLDDEST); + } + + /** + * Write the props part (if any) only, without newline + */ + private void writeProps(Writer out, boolean omitSig, boolean omitOldSig) throws IOException { + if (props == null) + return; + boolean started = false; + for (Map.Entry<Object, Object> e : props.entrySet()) { + String k = (String) e.getKey(); + if (omitSig && k.equals(PROP_SIG)) + continue; + if (omitOldSig && k.equals(PROP_OLDSIG)) + continue; + if (started) { + out.write(PROP_SEPARATOR); + } else { + started = true; + out.write(PROPS_SEPARATOR); } + String v = (String) e.getValue(); + out.write(k); + out.write(KV_SEPARATOR); + out.write(v); } - out.newLine(); } /** @@ -146,34 +181,19 @@ class HostTxtEntry { return false; if (!isValidated) { isValidated = true; - StringBuilder buf = new StringBuilder(1024); - String sig = null; + StringWriter buf = new StringWriter(1024); + String sig = props.getProperty(PROP_SIG); + if (sig == null) + return false; buf.append(name); buf.append(KV_SEPARATOR); buf.append(dest); - boolean started = false; - for (Map.Entry<Object, Object> e : props.entrySet()) { - String k = (String) e.getKey(); - String v = (String) e.getValue(); - if (k.equals(PROP_SIG)) { - if (sig != null) - return false; - sig = v; - // remove from the written data - continue; - } - if (started) { - buf.append(PROP_SEPARATOR); - } else { - started = true; - buf.append(PROPS_SEPARATOR); - } - buf.append(k); - buf.append(KV_SEPARATOR); - buf.append(v); - } - if (sig == null) + try { + writeProps(buf, true, false); + } catch (IOException ioe) { + // won't happen return false; + } byte[] sdata = Base64.decode(sig); if (sdata == null) return false; @@ -207,43 +227,20 @@ class HostTxtEntry { boolean rv = false; // don't cache result if (true) { - StringBuilder buf = new StringBuilder(1024); - String sig = null; - String olddest = null; + StringWriter buf = new StringWriter(1024); + String sig = props.getProperty(PROP_OLDSIG); + String olddest = props.getProperty(PROP_OLDDEST); + if (sig == null || olddest == null) + return false; buf.append(name); buf.append(KV_SEPARATOR); buf.append(dest); - boolean started = false; - for (Map.Entry<Object, Object> e : props.entrySet()) { - String k = (String) e.getKey(); - String v = (String) e.getValue(); - if (k.equals(PROP_SIG)) { - continue; - } - if (k.equals(PROP_OLDSIG)) { - if (sig != null) - return false; - sig = v; - // remove from the written data - continue; - } - if (k.equals(PROP_OLDDEST)) { - if (olddest != null) - return false; - olddest = v; - } - if (started) { - buf.append(PROP_SEPARATOR); - } else { - started = true; - buf.append(PROPS_SEPARATOR); - } - buf.append(k); - buf.append(KV_SEPARATOR); - buf.append(v); - } - if (sig == null || olddest == null) + try { + writeProps(buf, true, true); + } catch (IOException ioe) { + // won't happen return false; + } byte[] sdata = Base64.decode(sig); if (sdata == null) return false; @@ -309,25 +306,16 @@ class HostTxtEntry { private void signIt(SigningPrivateKey spk, String sigprop) { if (props == null) throw new IllegalStateException(); - StringBuilder buf = new StringBuilder(1024); + if (props.containsKey(sigprop)) + throw new IllegalStateException(); + StringWriter buf = new StringWriter(1024); buf.append(name); buf.append(KV_SEPARATOR); buf.append(dest); - boolean started = false; - for (Map.Entry<Object, Object> e : props.entrySet()) { - String k = (String) e.getKey(); - String v = (String) e.getValue(); - if (k.equals(sigprop)) - throw new IllegalStateException(); - if (started) { - buf.append(PROP_SEPARATOR); - } else { - started = true; - buf.append(PROPS_SEPARATOR); - } - buf.append(k); - buf.append(KV_SEPARATOR); - buf.append(v); + try { + writeProps(buf, false, false); + } catch (IOException ioe) { + throw new IllegalStateException(ioe); } Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk); if (s == null) @@ -336,34 +324,54 @@ class HostTxtEntry { } public static void main(String[] args) throws Exception { + int astart = 0; + if (args.length > 0 && args[0].equals("-i")) + astart++; + OrderedProperties props = new OrderedProperties(); + for (int i = astart; i < args.length; i++) { + int eq = args[i].indexOf("="); + props.setProperty(args[i].substring(0, eq), args[i].substring(eq + 1)); + } + props.setProperty("zzzz", "zzzzzzzzzzzzzzz"); // outer File f = new File("tmp-eepPriv.dat"); - // inner - File f2 = new File("tmp-eepPriv2.dat"); PrivateKeyFile pkf = new PrivateKeyFile(f); - PrivateKeyFile pkf2 = new PrivateKeyFile(f2); pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519); - pkf2.createIfAbsent(SigType.DSA_SHA1); - OrderedProperties props = new OrderedProperties(); - props.setProperty("c", "ccccccccccc"); - props.setProperty("a", "aaaa"); - props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64()); - HostTxtEntry he = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), props); + f.delete(); + PrivateKeyFile pkf2; + if (astart != 0) { + // inner + File f2 = new File("tmp-eepPriv2.dat"); + pkf2 = new PrivateKeyFile(f2); + pkf2.createIfAbsent(SigType.DSA_SHA1); + 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(); + //out.write("Before signing:\n"); + //he.write(out); + //out.flush(); SigningPrivateKey priv = pkf.getSigningPrivKey(); - SigningPrivateKey priv2 = pkf2.getSigningPrivKey(); - he.signInner(priv2); - out.write("After signing inner:\n"); - he.write(out); + if (astart != 0) { + SigningPrivateKey priv2 = pkf2.getSigningPrivKey(); + he.signInner(priv2); + //out.write("After signing inner:\n"); + //he.write(out); + } he.sign(priv); - out.write("After signing:\n"); + //out.write("After signing:\n"); he.write(out); out.flush(); - System.out.println("Orig has valid inner sig? " + he.hasValidInnerSig()); - System.out.println("Orig has valid sig? " + he.hasValidSig()); + if (astart > 0 && !he.hasValidInnerSig()) + throw new IllegalStateException("Inner fail 1"); + if (!he.hasValidSig()) + throw new IllegalStateException("Outer fail 1"); // now create 2nd, read in StringWriter sw = new StringWriter(1024); BufferedWriter buf = new BufferedWriter(sw); @@ -371,10 +379,12 @@ class HostTxtEntry { buf.flush(); String line = sw.toString(); line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2); - HostTxtEntry he2 = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), line); - System.out.println("Dupl. has valid inner sig? " + he2.hasValidInnerSig()); - System.out.println("Dupl. has valid sig? " + he2.hasValidSig()); - f.delete(); - f2.delete(); + HostTxtEntry he2 = new HostTxtEntry(host, pkf.getDestination().toBase64(), line); + if (astart > 0 && !he2.hasValidInnerSig()) + throw new IllegalStateException("Inner fail 2"); + if (!he2.hasValidSig()) + throw new IllegalStateException("Outer fail 2"); + //out.write("Test passed\n"); + //out.flush(); } } diff --git a/apps/addressbook/java/src/net/i2p/addressbook/HostTxtParser.java b/apps/addressbook/java/src/net/i2p/addressbook/HostTxtParser.java index f2c2df1491..92bbce817a 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/HostTxtParser.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/HostTxtParser.java @@ -217,7 +217,10 @@ class HostTxtParser { for (HostTxtEntry e : map.values()) { System.out.println("Host: " + e.getName() + "\nDest: " + e.getDest() + - "\nValid? " + e.hasValidSig()); + "\nAction: " + (e.getProps() != null ? e.getProps().getProperty("action") : "(none)") + + "\nValid Inner? " + e.hasValidInnerSig() + + "\nValid? " + e.hasValidSig() + + '\n'); } } diff --git a/core/java/src/net/metanotion/io/block/index/BSkipList.java b/core/java/src/net/metanotion/io/block/index/BSkipList.java index 5cb9c84bc0..70990a0e8f 100644 --- a/core/java/src/net/metanotion/io/block/index/BSkipList.java +++ b/core/java/src/net/metanotion/io/block/index/BSkipList.java @@ -206,6 +206,7 @@ public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V return new IBSkipIterator<K, V>(first, 0); } +/**** @Override public SkipIterator<K, V> min() { return iterator(); @@ -218,6 +219,7 @@ public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V SkipSpan<K, V> ss = stack.getEnd(); return new IBSkipIterator<K, V>(ss, ss.nKeys - 1); } +****/ @Override public SkipIterator<K, V> find(K key) { diff --git a/core/java/src/net/metanotion/io/data/LongBytes.java b/core/java/src/net/metanotion/io/data/LongBytes.java deleted file mode 100644 index cc1ed3c582..0000000000 --- a/core/java/src/net/metanotion/io/data/LongBytes.java +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (c) 2006, Matthew Estes -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - * Neither the name of Metanotion Software nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -package net.metanotion.io.data; - -import net.metanotion.io.Serializer; - -public class LongBytes implements Serializer<Long> { - public byte[] getBytes(Long o) { - byte[] b = new byte[8]; - long v = o.longValue(); - b[0] = (byte)(0xff & (v >> 56)); - b[1] = (byte)(0xff & (v >> 48)); - b[2] = (byte)(0xff & (v >> 40)); - b[3] = (byte)(0xff & (v >> 32)); - b[4] = (byte)(0xff & (v >> 24)); - b[5] = (byte)(0xff & (v >> 16)); - b[6] = (byte)(0xff & (v >> 8)); - b[7] = (byte)(0xff & v); - return b; - } - - public Long construct(byte[] b) { - long v =(((long)(b[0] & 0xff) << 56) | - ((long)(b[1] & 0xff) << 48) | - ((long)(b[2] & 0xff) << 40) | - ((long)(b[3] & 0xff) << 32) | - ((long)(b[4] & 0xff) << 24) | - ((long)(b[5] & 0xff) << 16) | - ((long)(b[6] & 0xff) << 8) | - (b[7] & 0xff)); - return Long.valueOf(v); - } -} diff --git a/core/java/src/net/metanotion/util/skiplist/SkipList.java b/core/java/src/net/metanotion/util/skiplist/SkipList.java index bb4226d780..e7c386cb5c 100644 --- a/core/java/src/net/metanotion/util/skiplist/SkipList.java +++ b/core/java/src/net/metanotion/util/skiplist/SkipList.java @@ -35,7 +35,7 @@ import net.i2p.util.RandomSource; //import net.metanotion.io.block.BlockFile; -public class SkipList<K extends Comparable<? super K>, V> implements Flushable { +public class SkipList<K extends Comparable<? super K>, V> implements Flushable, Iterable<V> { /** the probability of each next higher level */ protected static final int P = 2; private static final int MIN_SLOTS = 4; @@ -151,6 +151,7 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable { * dumps all the data * @deprecated goes to System.out */ + @Deprecated public void print() { System.out.println("List size " + size); System.out.println(first.print()); @@ -163,12 +164,14 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable { public SkipIterator<K, V> iterator() { return new SkipIterator<K, V>(first, 0); } +/**** public SkipIterator<K, V> min() { return new SkipIterator<K, V>(first, 0); } public SkipIterator<K, V> max() { SkipSpan<K, V> ss = stack.getEnd(); return new SkipIterator<K, V>(ss, ss.nKeys - 1); } +****/ /** @return an iterator where nextKey() is the first one greater than or equal to 'key' */ public SkipIterator<K, V> find(K key) { @@ -178,7 +181,6 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable { return new SkipIterator<K, V>(ss, search[0]); } - // Levels adjusted to guarantee O(log n) search // This is expensive proportional to the number of spans. public void balance() { -- GitLab