From 5f4dbfc98596fcdf565aadc4e3aec618196358e9 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Sun, 31 Jan 2016 18:11:20 +0100 Subject: [PATCH 1/7] Version 1.0.1-SNAPSHOT - fixed issue with requesting pubkey, and problem where your keys are overwritten if you try to import a contact again or worse, your identity as a contact --- build.gradle | 4 +-- .../dissem/bitmessage/BitmessageContext.java | 3 ++- .../dissem/bitmessage/ProofOfWorkService.java | 9 ++++--- .../bitmessage/entity/valueobject/Label.java | 1 + .../repository/JdbcAddressRepository.java | 26 ++++++++++++++----- .../repository/JdbcAddressRepositoryTest.java | 11 ++++++++ 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index dc918be..b944a14 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '1.0.0' + version = '1.0.1-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") @@ -34,7 +34,7 @@ subprojects { } signing { - required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } + required { isReleaseVersion } sign configurations.archives } diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index 28e8483..dbc08d3 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -200,6 +200,7 @@ public class BitmessageContext { LOG.info("Public key is missing from recipient. Requesting."); requestPubkey(msg.getFrom(), to); msg.setStatus(PUBKEY_REQUESTED); + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.OUTBOX)); ctx.getMessageRepository().save(msg); } else { LOG.info("Sending message."); @@ -224,7 +225,7 @@ public class BitmessageContext { requestingIdentity, address, new GetPubkey(address), - +28 * DAY + +2 * DAY ); } diff --git a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java index 19e231f..ecd1099 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java +++ b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java @@ -4,6 +4,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.PlaintextHolder; +import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.ports.MessageRepository; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import ch.dissem.bitmessage.ports.ProofOfWorkRepository; @@ -42,10 +43,10 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC } public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { - long nonceTrialsPerByte = recipient == null ? - ctx.getNetworkNonceTrialsPerByte() : recipient.getPubkey().getNonceTrialsPerByte(); - long extraBytes = recipient == null ? - ctx.getNetworkExtraBytes() : recipient.getPubkey().getExtraBytes(); + Pubkey pubkey = recipient == null ? null : recipient.getPubkey(); + + long nonceTrialsPerByte = pubkey == null ? ctx.getNetworkNonceTrialsPerByte() : pubkey.getNonceTrialsPerByte(); + long extraBytes = pubkey == null ? ctx.getNetworkExtraBytes() : pubkey.getExtraBytes(); powRepo.putObject(object, nonceTrialsPerByte, extraBytes); if (object.getPayload() instanceof PlaintextHolder) { diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java index 7c37973..02f0384 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java +++ b/core/src/main/java/ch/dissem/bitmessage/entity/valueobject/Label.java @@ -79,6 +79,7 @@ public class Label implements Serializable { INBOX, BROADCAST, DRAFT, + OUTBOX, SENT, UNREAD, TRASH diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java index 337d50a..bf15a6a 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -152,13 +152,25 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito private void update(BitmessageAddress address) throws IOException, SQLException { try (Connection connection = config.getConnection()) { - PreparedStatement ps = connection.prepareStatement( - "UPDATE Address SET alias=?, public_key=?, private_key=?, subscribed=? WHERE address=?"); - ps.setString(1, address.getAlias()); - writePubkey(ps, 2, address.getPubkey()); - writeBlob(ps, 3, address.getPrivateKey()); - ps.setBoolean(4, address.isSubscribed()); - ps.setString(5, address.getAddress()); + StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?"); + if (address.getPubkey() != null) { + statement.append(", public_key=?"); + } + if (address.getPrivateKey() != null) { + statement.append(", private_key=?"); + } + statement.append(", subscribed=? WHERE address=?"); + PreparedStatement ps = connection.prepareStatement(statement.toString()); + int i = 0; + ps.setString(++i, address.getAlias()); + if (address.getPubkey() != null) { + writePubkey(ps, ++i, address.getPubkey()); + } + if (address.getPrivateKey() != null) { + writeBlob(ps, ++i, address.getPrivateKey()); + } + ps.setBoolean(++i, address.isSubscribed()); + ps.setString(++i, address.getAddress()); ps.executeUpdate(); } } diff --git a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java index 18fc83c..18e70b2 100644 --- a/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java +++ b/repositories/src/test/java/ch/dissem/bitmessage/repository/JdbcAddressRepositoryTest.java @@ -128,6 +128,17 @@ public class JdbcAddressRepositoryTest extends TestBase { assertEquals("Test-Alias", address.getAlias()); } + @Test + public void ensureExistingKeysAreNotDeleted() { + BitmessageAddress address = new BitmessageAddress(IDENTITY_A); + address.setAlias("Test"); + repo.save(address); + BitmessageAddress identityA = repo.getAddress(IDENTITY_A); + assertNotNull(identityA.getPubkey()); + assertNotNull(identityA.getPrivateKey()); + assertEquals("Test", identityA.getAlias()); + } + @Test public void testRemove() throws Exception { BitmessageAddress address = repo.getAddress(IDENTITY_A); From edd8045327bb4d13eae4aed7eff1cd730faf7d64 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Tue, 2 Feb 2016 20:40:01 +0100 Subject: [PATCH 2/7] Fixed / improved message sending and added a system test (it's a start) --- .../dissem/bitmessage/BitmessageContext.java | 137 ++++-------------- .../ch/dissem/bitmessage/InternalContext.java | 66 ++++++++- .../ch/dissem/bitmessage/utils/Numbers.java | 2 +- demo/build.gradle | 1 + .../java/ch/dissem/bitmessage/SystemTest.java | 79 ++++++++++ .../ch/dissem/bitmessage/TestListener.java | 26 ++++ .../dissem/bitmessage/TestNodeRegistry.java | 51 +++++++ 7 files changed, 246 insertions(+), 116 deletions(-) create mode 100644 demo/src/test/java/ch/dissem/bitmessage/SystemTest.java create mode 100644 demo/src/test/java/ch/dissem/bitmessage/TestListener.java create mode 100644 demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index dbc08d3..dde6d2d 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -17,20 +17,21 @@ package ch.dissem.bitmessage; import ch.dissem.bitmessage.entity.*; -import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.entity.payload.Broadcast; +import ch.dissem.bitmessage.entity.payload.Msg; +import ch.dissem.bitmessage.entity.payload.ObjectPayload; +import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; -import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Property; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.InetAddress; -import java.util.Arrays; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.*; @@ -38,9 +39,7 @@ import java.util.concurrent.*; import static ch.dissem.bitmessage.entity.Plaintext.Status.*; import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST; import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; -import static ch.dissem.bitmessage.utils.UnixTime.DAY; -import static ch.dissem.bitmessage.utils.UnixTime.HOUR; -import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; +import static ch.dissem.bitmessage.utils.UnixTime.*; /** *

Use this class if you want to create a Bitmessage client.

@@ -122,67 +121,24 @@ public class BitmessageContext { } public void broadcast(final BitmessageAddress from, final String subject, final String message) { - pool.submit(new Runnable() { - @Override - public void run() { - Plaintext msg = new Plaintext.Builder(BROADCAST) - .from(from) - .message(subject, message) - .build(); - - LOG.info("Sending message."); - msg.setStatus(DOING_PROOF_OF_WORK); - ctx.getMessageRepository().save(msg); - ctx.send( - from, - from, - Factory.getBroadcast(from, msg), - +2 * DAY - ); - msg.setStatus(SENT); - msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.BROADCAST, Label.Type.SENT)); - ctx.getMessageRepository().save(msg); - } - }); + Plaintext msg = new Plaintext.Builder(BROADCAST) + .from(from) + .message(subject, message) + .build(); + send(msg); } public void send(final BitmessageAddress from, final BitmessageAddress to, final String subject, final String message) { if (from.getPrivateKey() == null) { throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key."); } - pool.submit(new Runnable() { - @Override - public void run() { - Plaintext msg = new Plaintext.Builder(MSG) - .from(from) - .to(to) - .message(subject, message) - .labels(messages().getLabels(Label.Type.SENT)) - .build(); - if (to.getPubkey() == null) { - tryToFindMatchingPubkey(to); - } - if (to.getPubkey() == null) { - LOG.info("Public key is missing from recipient. Requesting."); - requestPubkey(from, to); - msg.setStatus(PUBKEY_REQUESTED); - ctx.getMessageRepository().save(msg); - } else { - LOG.info("Sending message."); - msg.setStatus(DOING_PROOF_OF_WORK); - ctx.getMessageRepository().save(msg); - ctx.send( - from, - to, - new Msg(msg), - +2 * DAY - ); - msg.setStatus(SENT); - msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); - ctx.getMessageRepository().save(msg); - } - } - }); + Plaintext msg = new Plaintext.Builder(MSG) + .from(from) + .to(to) + .message(subject, message) + .labels(messages().getLabels(Label.Type.SENT)) + .build(); + send(msg); } public void send(final Plaintext msg) { @@ -193,16 +149,18 @@ public class BitmessageContext { @Override public void run() { BitmessageAddress to = msg.getTo(); - if (to.getPubkey() == null) { - tryToFindMatchingPubkey(to); + if (to != null) { + if (to.getPubkey() == null) { + LOG.info("Public key is missing from recipient. Requesting."); + ctx.requestPubkey(to); + } + if (to.getPubkey() == null) { + msg.setStatus(PUBKEY_REQUESTED); + msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.OUTBOX)); + ctx.getMessageRepository().save(msg); + } } - if (to.getPubkey() == null) { - LOG.info("Public key is missing from recipient. Requesting."); - requestPubkey(msg.getFrom(), to); - msg.setStatus(PUBKEY_REQUESTED); - msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.OUTBOX)); - ctx.getMessageRepository().save(msg); - } else { + if (to == null || to.getPubkey() != null) { LOG.info("Sending message."); msg.setStatus(DOING_PROOF_OF_WORK); ctx.getMessageRepository().save(msg); @@ -220,15 +178,6 @@ public class BitmessageContext { }); } - private void requestPubkey(BitmessageAddress requestingIdentity, BitmessageAddress address) { - ctx.send( - requestingIdentity, - address, - new GetPubkey(address), - +2 * DAY - ); - } - public void startup() { ctx.getNetworkHandler().start(networkListener); } @@ -281,41 +230,11 @@ public class BitmessageContext { public void addContact(BitmessageAddress contact) { ctx.getAddressRepository().save(contact); - tryToFindMatchingPubkey(contact); if (contact.getPubkey() == null) { ctx.requestPubkey(contact); } } - private void tryToFindMatchingPubkey(BitmessageAddress address) { - for (ObjectMessage object : ctx.getInventory().getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY)) { - try { - Pubkey pubkey = (Pubkey) object.getPayload(); - if (address.getVersion() == 4) { - V4Pubkey v4Pubkey = (V4Pubkey) pubkey; - if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) { - v4Pubkey.decrypt(address.getPublicDecryptionKey()); - if (object.isSignatureValid(v4Pubkey)) { - address.setPubkey(v4Pubkey); - ctx.getAddressRepository().save(address); - break; - } else { - LOG.info("Found pubkey for " + address + " but signature is invalid"); - } - } - } else { - if (Arrays.equals(pubkey.getRipe(), address.getRipe())) { - address.setPubkey(pubkey); - ctx.getAddressRepository().save(address); - break; - } - } - } catch (Exception e) { - LOG.debug(e.getMessage(), e); - } - } - } - public void addSubscribtion(BitmessageAddress address) { address.setSubscribed(true); ctx.getAddressRepository().save(address); diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index 9971b9b..54e81a9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -19,9 +19,7 @@ package ch.dissem.bitmessage; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Encrypted; import ch.dissem.bitmessage.entity.ObjectMessage; -import ch.dissem.bitmessage.entity.payload.Broadcast; -import ch.dissem.bitmessage.entity.payload.GetPubkey; -import ch.dissem.bitmessage.entity.payload.ObjectPayload; +import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.UnixTime; @@ -29,6 +27,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Arrays; import java.util.TreeSet; /** @@ -212,16 +211,71 @@ public class InternalContext { } } + /** + * Be aware that if the pubkey already exists in the inventory, the metods will not request it and the callback + * for freshly received pubkeys will not be called. Instead the pubkey is added to the contact and stored on DB. + */ public void requestPubkey(final BitmessageAddress contact) { + BitmessageAddress stored = addressRepository.getAddress(contact.getAddress()); + + tryToFindMatchingPubkey(contact); + if (contact.getPubkey() != null) { + if (stored != null) { + stored.setPubkey(contact.getPubkey()); + addressRepository.save(stored); + } else { + addressRepository.save(contact); + } + return; + } + + if (stored == null) { + addressRepository.save(contact); + } + long expires = UnixTime.now(+pubkeyTTL); LOG.info("Expires at " + expires); - final ObjectMessage response = new ObjectMessage.Builder() + final ObjectMessage request = new ObjectMessage.Builder() .stream(contact.getStream()) .expiresTime(expires) .payload(new GetPubkey(contact)) .build(); - messageCallback.proofOfWorkStarted(response.getPayload()); - proofOfWorkService.doProofOfWork(response); + messageCallback.proofOfWorkStarted(request.getPayload()); + proofOfWorkService.doProofOfWork(request); + } + + private void tryToFindMatchingPubkey(BitmessageAddress address) { + BitmessageAddress stored = addressRepository.getAddress(address.getAddress()); + if (stored != null) { + address.setAlias(stored.getAlias()); + address.setSubscribed(stored.isSubscribed()); + } + for (ObjectMessage object : inventory.getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY)) { + try { + Pubkey pubkey = (Pubkey) object.getPayload(); + if (address.getVersion() == 4) { + V4Pubkey v4Pubkey = (V4Pubkey) pubkey; + if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) { + v4Pubkey.decrypt(address.getPublicDecryptionKey()); + if (object.isSignatureValid(v4Pubkey)) { + address.setPubkey(v4Pubkey); + addressRepository.save(address); + break; + } else { + LOG.info("Found pubkey for " + address + " but signature is invalid"); + } + } + } else { + if (Arrays.equals(pubkey.getRipe(), address.getRipe())) { + address.setPubkey(pubkey); + addressRepository.save(address); + break; + } + } + } catch (Exception e) { + LOG.debug(e.getMessage(), e); + } + } } public long getClientNonce() { diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java b/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java index b1ace02..9d0c078 100644 --- a/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java +++ b/core/src/main/java/ch/dissem/bitmessage/utils/Numbers.java @@ -1,7 +1,7 @@ package ch.dissem.bitmessage.utils; /** - * Created by chrig on 07.12.2015. + * @author Christian Basler */ public class Numbers { public static long max(long a, long b) { diff --git a/demo/build.gradle b/demo/build.gradle index 84d5907..2ab6363 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -30,4 +30,5 @@ dependencies { compile 'args4j:args4j:2.32' compile 'com.h2database:h2:1.4.190' testCompile 'junit:junit:4.11' + testCompile 'org.mockito:mockito-core:1.10.19' } diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java new file mode 100644 index 0000000..5bf2949 --- /dev/null +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -0,0 +1,79 @@ +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.networking.DefaultNetworkHandler; +import ch.dissem.bitmessage.repository.*; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * @author Christian Basler + */ +public class SystemTest { + static BitmessageContext alice; + static TestListener aliceListener = new TestListener(); + static BitmessageAddress aliceIdentity; + + static BitmessageContext bob; + static TestListener bobListener = new TestListener(); + static BitmessageAddress bobIdentity; + + @BeforeClass + public static void setUp() { + JdbcConfig aliceDB = new JdbcConfig("jdbc:h2:mem:alice;DB_CLOSE_DELAY=-1", "sa", ""); + alice = new BitmessageContext.Builder() + .addressRepo(new JdbcAddressRepository(aliceDB)) + .inventory(new JdbcInventory(aliceDB)) + .messageRepo(new JdbcMessageRepository(aliceDB)) + .powRepo(new JdbcProofOfWorkRepository(aliceDB)) + .port(6001) + .nodeRegistry(new TestNodeRegistry(6002)) + .networkHandler(new DefaultNetworkHandler()) + .cryptography(new BouncyCryptography()) + .listener(aliceListener) + .build(); + alice.startup(); + aliceIdentity = alice.createIdentity(false); + + JdbcConfig bobDB = new JdbcConfig("jdbc:h2:mem:bob;DB_CLOSE_DELAY=-1", "sa", ""); + bob = new BitmessageContext.Builder() + .addressRepo(new JdbcAddressRepository(bobDB)) + .inventory(new JdbcInventory(bobDB)) + .messageRepo(new JdbcMessageRepository(bobDB)) + .powRepo(new JdbcProofOfWorkRepository(bobDB)) + .port(6002) + .nodeRegistry(new TestNodeRegistry(6001)) + .networkHandler(new DefaultNetworkHandler()) + .cryptography(new BouncyCryptography()) + .listener(bobListener) + .build(); + bob.startup(); + bobIdentity = bob.createIdentity(false); + } + + @AfterClass + public static void tearDown() { + alice.shutdown(); + bob.shutdown(); + } + + @Test + public void ensureAliceCanSendMessageToBob() throws Exception { + bobListener.reset(); + String originalMessage = UUID.randomUUID().toString(); + alice.send(aliceIdentity, new BitmessageAddress(bobIdentity.getAddress()), "Subject", originalMessage); + + Plaintext plaintext = bobListener.get(5, TimeUnit.MINUTES); + + assertThat(plaintext.getText(), equalTo(originalMessage)); + } +} diff --git a/demo/src/test/java/ch/dissem/bitmessage/TestListener.java b/demo/src/test/java/ch/dissem/bitmessage/TestListener.java new file mode 100644 index 0000000..9c00776 --- /dev/null +++ b/demo/src/test/java/ch/dissem/bitmessage/TestListener.java @@ -0,0 +1,26 @@ +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.entity.Plaintext; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +/** + * Created by chrig on 02.02.2016. + */ +public class TestListener implements BitmessageContext.Listener { + private CompletableFuture future = new CompletableFuture<>(); + + @Override + public void receive(Plaintext plaintext) { + future.complete(plaintext); + } + + public void reset() { + future = new CompletableFuture<>(); + } + + public Plaintext get(long timeout, TimeUnit unit) throws Exception { + return future.get(timeout, unit); + } +} diff --git a/demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java b/demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java new file mode 100644 index 0000000..71750ed --- /dev/null +++ b/demo/src/test/java/ch/dissem/bitmessage/TestNodeRegistry.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Christian Basler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.dissem.bitmessage; + +import ch.dissem.bitmessage.entity.valueobject.NetworkAddress; +import ch.dissem.bitmessage.ports.NodeRegistry; + +import java.util.LinkedList; +import java.util.List; + +/** + * Empty {@link NodeRegistry} that doesn't do anything, but shouldn't break things either. + */ +class TestNodeRegistry implements NodeRegistry { + private List<NetworkAddress> nodes = new LinkedList<>(); + + public TestNodeRegistry(int... ports) { + for (int port : ports) { + nodes.add( + new NetworkAddress.Builder() + .ipv4(127, 0, 0, 1) + .port(port) + .build() + ); + } + } + + @Override + public List<NetworkAddress> getKnownAddresses(int limit, long... streams) { + return nodes; + } + + @Override + public void offerAddresses(List<NetworkAddress> addresses) { + // Ignore + } +} From 985e830779a18990ca67b9e56ce49ec3bfc012dd Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 2 Feb 2016 21:05:14 +0100 Subject: [PATCH 3/7] Made TTLs easily changeable (albeit not for specific messages) This should make the system test run on Travis CI again --- .../dissem/bitmessage/BitmessageContext.java | 6 +-- .../ch/dissem/bitmessage/InternalContext.java | 7 ++-- .../java/ch/dissem/bitmessage/utils/TTL.java | 40 +++++++++++++++++++ .../bitmessage/security/CryptographyTest.java | 10 ++--- .../java/ch/dissem/bitmessage/SystemTest.java | 6 +++ 5 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/ch/dissem/bitmessage/utils/TTL.java diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index dde6d2d..c99acfb 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -28,6 +28,7 @@ import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Property; +import ch.dissem.bitmessage.utils.TTL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -168,7 +169,7 @@ public class BitmessageContext { msg.getFrom(), to, new Msg(msg), - +2 * DAY + TTL.msg() ); msg.setStatus(SENT); msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); @@ -288,7 +289,6 @@ public class BitmessageContext { int connectionLimit = 150; long connectionTTL = 30 * MINUTE; boolean sendPubkeyOnIdentityCreation = true; - long pubkeyTTL = 28; public Builder() { } @@ -383,7 +383,7 @@ public class BitmessageContext { */ public Builder pubkeyTTL(long days) { if (days < 0 || days > 28 * DAY) throw new IllegalArgumentException("TTL must be between 1 and 28 days"); - this.pubkeyTTL = days; + TTL.pubkey(days); return this; } diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java index 54e81a9..bfd4f30 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java @@ -22,6 +22,7 @@ import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.*; import ch.dissem.bitmessage.ports.*; import ch.dissem.bitmessage.utils.Singleton; +import ch.dissem.bitmessage.utils.TTL; import ch.dissem.bitmessage.utils.UnixTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,7 +59,6 @@ public class InternalContext { private final long clientNonce; private final long networkNonceTrialsPerByte = 1000; private final long networkExtraBytes = 1000; - private final long pubkeyTTL; private long connectionTTL; private int connectionLimit; @@ -78,7 +78,6 @@ public class InternalContext { this.port = builder.port; this.connectionLimit = builder.connectionLimit; this.connectionTTL = builder.connectionTTL; - this.pubkeyTTL = builder.pubkeyTTL; Singleton.initialize(cryptography); @@ -194,7 +193,7 @@ public class InternalContext { public void sendPubkey(final BitmessageAddress identity, final long targetStream) { try { - long expires = UnixTime.now(pubkeyTTL); + long expires = UnixTime.now(TTL.pubkey()); LOG.info("Expires at " + expires); final ObjectMessage response = new ObjectMessage.Builder() .stream(targetStream) @@ -233,7 +232,7 @@ public class InternalContext { addressRepository.save(contact); } - long expires = UnixTime.now(+pubkeyTTL); + long expires = UnixTime.now(TTL.getpubkey()); LOG.info("Expires at " + expires); final ObjectMessage request = new ObjectMessage.Builder() .stream(contact.getStream()) diff --git a/core/src/main/java/ch/dissem/bitmessage/utils/TTL.java b/core/src/main/java/ch/dissem/bitmessage/utils/TTL.java new file mode 100644 index 0000000..17e31e5 --- /dev/null +++ b/core/src/main/java/ch/dissem/bitmessage/utils/TTL.java @@ -0,0 +1,40 @@ +package ch.dissem.bitmessage.utils; + +import static ch.dissem.bitmessage.utils.UnixTime.DAY; + +/** + * Stores times to live for different object types. Usually this shouldn't be messed with, + * but for tests it might be a good idea to reduce it to a minimum, and on mobile clients + * you might want to optimize it as well. + * + * @author Christian Basler + */ +public class TTL { + private static long msg = 2 * DAY; + private static long getpubkey = 2 * DAY; + private static long pubkey = 28 * DAY; + + public static long msg() { + return msg; + } + + public static void msg(long msg) { + TTL.msg = msg; + } + + public static long getpubkey() { + return getpubkey; + } + + public static void getpubkey(long getpubkey) { + TTL.getpubkey = getpubkey; + } + + public static long pubkey() { + return pubkey; + } + + public static void pubkey(long pubkey) { + TTL.pubkey = pubkey; + } +} diff --git a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java index 3a68968..d4ab2ad 100644 --- a/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java +++ b/cryptography-bc/src/test/java/ch/dissem/bitmessage/security/CryptographyTest.java @@ -1,11 +1,11 @@ package ch.dissem.bitmessage.security; import ch.dissem.bitmessage.InternalContext; +import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.GenericPayload; import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; -import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; import ch.dissem.bitmessage.utils.CallbackWaiter; import ch.dissem.bitmessage.utils.Singleton; import ch.dissem.bitmessage.utils.UnixTime; @@ -15,13 +15,13 @@ import javax.xml.bind.DatatypeConverter; import java.io.ByteArrayInputStream; import java.io.IOException; -import static ch.dissem.bitmessage.utils.UnixTime.DAY; +import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static org.junit.Assert.assertArrayEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** - * Created by chris on 19.07.15. + * @author Christian Basler */ public class CryptographyTest { public static final byte[] TEST_VALUE = "teststring".getBytes(); @@ -72,7 +72,7 @@ public class CryptographyTest { public void testProofOfWorkFails() throws IOException { ObjectMessage objectMessage = new ObjectMessage.Builder() .nonce(new byte[8]) - .expiresTime(UnixTime.now(+2 * DAY)) // 5 minutes + .expiresTime(UnixTime.now(+2 * MINUTE)) .objectType(0) .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) .build(); @@ -83,7 +83,7 @@ public class CryptographyTest { public void testDoProofOfWork() throws Exception { ObjectMessage objectMessage = new ObjectMessage.Builder() .nonce(new byte[8]) - .expiresTime(UnixTime.now(+2 * DAY)) + .expiresTime(UnixTime.now(+2 * MINUTE)) .objectType(0) .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) .build(); diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java index 5bf2949..fd73dcf 100644 --- a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -5,6 +5,8 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.repository.*; +import ch.dissem.bitmessage.utils.TTL; +import ch.dissem.bitmessage.utils.UnixTime; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -12,6 +14,7 @@ import org.junit.Test; import java.util.UUID; import java.util.concurrent.TimeUnit; +import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; @@ -29,6 +32,9 @@ public class SystemTest { @BeforeClass public static void setUp() { + TTL.msg(5 * MINUTE); + TTL.getpubkey(5 * MINUTE); + TTL.pubkey(5 * MINUTE); JdbcConfig aliceDB = new JdbcConfig("jdbc:h2:mem:alice;DB_CLOSE_DELAY=-1", "sa", ""); alice = new BitmessageContext.Builder() .addressRepo(new JdbcAddressRepository(aliceDB)) From 91c41fa3bd441214bfa537414a6ec010be6e1b3e Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Tue, 2 Feb 2016 21:23:15 +0100 Subject: [PATCH 4/7] Version 1.0.1 bump --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b944a14..68fb5bc 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ subprojects { sourceCompatibility = 1.7 group = 'ch.dissem.jabit' - version = '1.0.1-SNAPSHOT' + version = '1.0.1' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") From b1599cbd60d98d3067775dd97f459bcbcff053ab Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 07:52:22 +0100 Subject: [PATCH 5/7] This should fix the build on Travis CI / machines that don't have signing configured --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 68fb5bc..0f6cf26 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ subprojects { } signing { - required { isReleaseVersion } + required { isReleaseVersion && project.getProperties().get("signing.keyId")?.length() > 0 } sign configurations.archives } From 354f50687233aa2c4f60ecaf96a4d2aca37870cf Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Wed, 3 Feb 2016 19:28:41 +0100 Subject: [PATCH 6/7] Raised timeout for test so hopefully it doesn't fail anymore on Travis CI (otherwise there must be a different problem) --- demo/src/test/java/ch/dissem/bitmessage/SystemTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java index fd73dcf..1309336 100644 --- a/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java +++ b/demo/src/test/java/ch/dissem/bitmessage/SystemTest.java @@ -6,7 +6,6 @@ import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.networking.DefaultNetworkHandler; import ch.dissem.bitmessage.repository.*; import ch.dissem.bitmessage.utils.TTL; -import ch.dissem.bitmessage.utils.UnixTime; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -78,7 +77,7 @@ public class SystemTest { String originalMessage = UUID.randomUUID().toString(); alice.send(aliceIdentity, new BitmessageAddress(bobIdentity.getAddress()), "Subject", originalMessage); - Plaintext plaintext = bobListener.get(5, TimeUnit.MINUTES); + Plaintext plaintext = bobListener.get(15, TimeUnit.MINUTES); assertThat(plaintext.getText(), equalTo(originalMessage)); } From 9231cf5eaa9766a0b6bb3a48cb7fe36badeabea4 Mon Sep 17 00:00:00 2001 From: Christian Basler <chrigu.meyer@gmail.com> Date: Thu, 4 Feb 2016 10:12:43 +0100 Subject: [PATCH 7/7] Skip system tests by default as they don't work on Travis CI --- demo/build.gradle | 2 ++ gradle.properties | 1 + 2 files changed, 3 insertions(+) diff --git a/demo/build.gradle b/demo/build.gradle index 2ab6363..d87b0f3 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -16,6 +16,8 @@ uploadArchives { sourceCompatibility = 1.8 +test.enabled = Boolean.valueOf(systemTestsEnabled) + task fatCapsule(type: FatCapsule) { applicationClass 'ch.dissem.bitmessage.demo.Main' } diff --git a/gradle.properties b/gradle.properties index eb6ed30..bb8beb4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,3 +8,4 @@ signing.password= ossrhUsername= ossrhPassword= +systemTestsEnabled=false \ No newline at end of file