/* * This file is part of Bitsquare. * * Bitsquare is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * Bitsquare is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Bitsquare. If not, see . */ package io.bitsquare.msg.tomp2p; import java.io.IOException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.util.Random; import net.tomp2p.connection.Ports; import net.tomp2p.dht.FutureGet; import net.tomp2p.dht.FuturePut; import net.tomp2p.dht.FutureRemove; import net.tomp2p.dht.PeerBuilderDHT; import net.tomp2p.dht.PeerDHT; import net.tomp2p.dht.UtilsDHT2; import net.tomp2p.futures.FutureDirect; import net.tomp2p.p2p.PeerBuilder; import net.tomp2p.peers.Number160; import net.tomp2p.peers.PeerAddress; import net.tomp2p.rpc.ObjectDataReply; import net.tomp2p.storage.Data; import net.tomp2p.utils.Utils; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.junit.Assert.*; // TODO Reactivate tests when TomP2PNode is using original code again. we deactivated the security features atm. // cause IOException: Not listening to anything. Maybe your binding information is wrong. // investigate what has broken it, probably from update to latest head @Ignore public class TomP2PNodeTest { private static final Logger log = LoggerFactory.getLogger(TomP2PNodeTest.class); final private static Random rnd = new Random(42L); @Test public void testSendData() throws Exception { PeerDHT[] peers = UtilsDHT2.createNodes(3, rnd, new Ports().tcpPort()); PeerDHT master = peers[0]; PeerDHT client = peers[1]; PeerDHT otherPeer = peers[2]; UtilsDHT2.perfectRouting(peers); for (final PeerDHT peer : peers) { peer.peer().objectDataReply(new ObjectDataReply() { @Override public Object reply(PeerAddress sender, Object request) throws Exception { return true; } }); } final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); keyGen.initialize(1024); KeyPair keyPairClient = keyGen.genKeyPair(); KeyPair keyPairOtherPeer = keyGen.genKeyPair(); TomP2PNode node; Number160 locationKey; Object object; FutureDirect futureDirect; node = new TomP2PNode(keyPairClient, client); object = "clients data"; futureDirect = node.sendData(otherPeer.peerAddress(), object); futureDirect.awaitUninterruptibly(); assertTrue(futureDirect.isSuccess()); // we return true from objectDataReply assertTrue((Boolean) futureDirect.object()); master.shutdown(); } @Test public void testProtectedPutGet() throws Exception { PeerDHT[] peers = UtilsDHT2.createNodes(3, rnd, new Ports().tcpPort()); PeerDHT master = peers[0]; PeerDHT client = peers[1]; PeerDHT otherPeer = peers[2]; UtilsDHT2.perfectRouting(peers); final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); keyGen.initialize(1024); KeyPair keyPairClient = keyGen.genKeyPair(); KeyPair keyPairOtherPeer = keyGen.genKeyPair(); TomP2PNode node; Number160 locationKey; Data data; FuturePut futurePut; FutureGet futureGet; // otherPeer tries to squat clients location store // he can do it but as he has not the domain key of the client he cannot do any harm // he only can store und that path: locationKey.otherPeerDomainKey.data node = new TomP2PNode(keyPairOtherPeer, otherPeer); locationKey = Number160.createHash("clients location"); data = new Data("otherPeer data"); futurePut = node.putDomainProtectedData(locationKey, data); futurePut.awaitUninterruptibly(); assertTrue(futurePut.isSuccess()); futureGet = node.getDomainProtectedData(locationKey, keyPairOtherPeer.getPublic()); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); assertEquals("otherPeer data", futureGet.data().object()); // client store his data und his domainkey, no problem with previous occupied // he only can store und that path: locationKey.clientDomainKey.data node = new TomP2PNode(keyPairClient, client); locationKey = Number160.createHash("clients location"); data = new Data("client data"); futurePut = node.putDomainProtectedData(locationKey, data); futurePut.awaitUninterruptibly(); assertTrue(futurePut.isSuccess()); futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic()); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); assertEquals("client data", futureGet.data().object()); // also other peers can read that data if they know the public key of the client node = new TomP2PNode(keyPairOtherPeer, otherPeer); futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic()); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); assertEquals("client data", futureGet.data().object()); // other peer try to use pub key of other peer as domain key hash. // must fail as he don't have the full key pair (private key of client missing) locationKey = Number160.createHash("clients location"); data = new Data("otherPeer data hack"); data.protectEntry(keyPairOtherPeer); // he use the pub key from the client final Number160 keyHash = Utils.makeSHAHash(keyPairClient.getPublic().getEncoded()); futurePut = otherPeer.put(locationKey).data(data).keyPair(keyPairOtherPeer).domainKey(keyHash) .protectDomain().start(); futurePut.awaitUninterruptibly(); assertFalse(futurePut.isSuccess()); // he can read his prev. stored data node = new TomP2PNode(keyPairOtherPeer, otherPeer); futureGet = node.getDomainProtectedData(locationKey, keyPairOtherPeer.getPublic()); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); assertEquals("otherPeer data", futureGet.data().object()); // he can read clients data futureGet = node.getDomainProtectedData(locationKey, keyPairClient.getPublic()); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); assertEquals("client data", futureGet.data().object()); master.shutdown(); } @Test public void testChangeEntryProtectionKey() throws Exception { KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA"); KeyPair keyPair1 = gen.generateKeyPair(); KeyPair keyPair2 = gen.generateKeyPair(); PeerDHT p1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash(1)).ports(4838) .keyPair(keyPair1).start()).start(); PeerDHT p2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash(2)).ports(4839) .keyPair(keyPair2).start()).start(); p2.peer().bootstrap().peerAddress(p1.peerAddress()).start().awaitUninterruptibly(); p1.peer().bootstrap().peerAddress(p2.peerAddress()).start().awaitUninterruptibly(); Data data = new Data("test").protectEntry(keyPair1); FuturePut fp1 = p1.put(Number160.createHash("key1")).sign().data(data).start().awaitUninterruptibly(); Assert.assertTrue(fp1.isSuccess()); FuturePut fp2 = p2.put(Number160.createHash("key1")).data(data).start().awaitUninterruptibly(); Assert.assertTrue(!fp2.isSuccess()); Data data2 = new Data().protectEntry(keyPair2); data2.publicKey(keyPair2.getPublic()); FuturePut fp3 = p1.put(Number160.createHash("key1")).sign().putMeta().data(data2).start().awaitUninterruptibly(); Assert.assertTrue(fp3.isSuccess()); FuturePut fp4 = p2.put(Number160.createHash("key1")).sign().data(data).start().awaitUninterruptibly(); Assert.assertTrue(fp4.isSuccess()); p1.shutdown().awaitUninterruptibly(); p2.shutdown().awaitUninterruptibly(); } @Test public void testAddToListGetList() throws Exception { PeerDHT[] peers = UtilsDHT2.createNodes(3, rnd, new Ports().tcpPort()); PeerDHT master = peers[0]; PeerDHT client = peers[1]; PeerDHT otherPeer = peers[2]; UtilsDHT2.perfectRouting(peers); TomP2PNode node; final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); keyGen.initialize(1024); KeyPair keyPairClient = keyGen.genKeyPair(); KeyPair keyPairOtherPeer = keyGen.genKeyPair(); Number160 locationKey; Data data; FuturePut futurePut; FutureGet futureGet; // client add a value KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA"); KeyPair keyPair1 = gen.generateKeyPair(); keyPairClient = keyPair1; node = new TomP2PNode(keyPairClient, client); locationKey = Number160.createHash("add to list clients location"); data = new Data("add to list client data1"); Data data_1 = data; futurePut = node.addProtectedData(locationKey, data); futurePut.awaitUninterruptibly(); assertTrue(futurePut.isSuccess()); data = new Data("add to list client data2"); Data data_2 = data; futurePut = node.addProtectedData(locationKey, data); futurePut.awaitUninterruptibly(); assertTrue(futurePut.isSuccess()); futureGet = node.getDataMap(locationKey); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); boolean foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data1"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); boolean foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data2"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); assertTrue(foundData1); assertTrue(foundData2); assertEquals(2, futureGet.dataMap().values().size()); // other peer tried to overwrite that entry // but will not succeed, instead he will add a new entry. // TODO investigate why it is not possible to overwrite the entry with that method // The protection entry with the key does not make any difference as also the client himself cannot overwrite // any entry // http://tomp2p.net/doc/P2P-with-TomP2P-1.pdf // "add(location_key, value) is translated to put(location_key, hash(value), value)" // fake content key with content key from previous clients entry Number160 contentKey = Number160.createHash("add to list client data1"); data = new Data("add to list other peer data HACK!"); data.protectEntry(keyPairOtherPeer); // also with client key it does not work... futurePut = otherPeer.put(locationKey).data(contentKey, data).keyPair(keyPairOtherPeer).start(); futurePut.awaitUninterruptibly(); assertTrue(futurePut.isSuccess()); node = new TomP2PNode(keyPairOtherPeer, otherPeer); futureGet = node.getDataMap(locationKey); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data1"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data2"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); boolean foundData3 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list other peer data HACK!"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); assertTrue(foundData1); assertTrue(foundData2); assertTrue(foundData3); assertEquals(3, futureGet.dataMap().values().size()); // client removes his entry -> OK node = new TomP2PNode(keyPairClient, client); FutureRemove futureRemove = node.removeFromDataMap(locationKey, data_1); futureRemove.awaitUninterruptibly(); assertTrue(futureRemove.isSuccess()); futureGet = node.getDataMap(locationKey); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data1"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data2"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); foundData3 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list other peer data HACK!"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); assertFalse(foundData1); assertTrue(foundData2); assertTrue(foundData3); assertEquals(2, futureGet.dataMap().values().size()); // otherPeer tries to removes client entry -> FAIL node = new TomP2PNode(keyPairOtherPeer, otherPeer); futureRemove = node.removeFromDataMap(locationKey, data_2); futureRemove.awaitUninterruptibly(); assertFalse(futureRemove.isSuccess()); futureGet = node.getDataMap(locationKey); futureGet.awaitUninterruptibly(); assertTrue(futureGet.isSuccess()); foundData1 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data1"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); foundData2 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list client data2"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); foundData3 = futureGet.dataMap().values().stream().anyMatch(data1 -> { try { return data1.object().equals("add to list other peer data HACK!"); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } return false; }); assertFalse(foundData1); assertTrue(foundData2); assertTrue(foundData3); assertEquals(2, futureGet.dataMap().values().size()); master.shutdown(); } }