From b793526f2f8d8ddc0af0508c69b9cf71bf3fd664 Mon Sep 17 00:00:00 2001 From: Christian Basler Date: Sat, 23 May 2015 10:27:05 +0200 Subject: [PATCH] Inventory items are now saved only if processing didn't fail. Receiving messages works, but there seems to be a problem with the POW check in some circumstances. --- .../dissem/bitmessage/demo/Application.java | 8 +++---- .../dissem/bitmessage/BitmessageContext.java | 6 +---- .../bitmessage/DefaultMessageListener.java | 20 ++++++++++------- .../dissem/bitmessage/entity/Encrypted.java | 4 +++- .../bitmessage/entity/ObjectMessage.java | 5 +++-- .../dissem/bitmessage/entity/Plaintext.java | 7 ++---- .../bitmessage/entity/payload/Broadcast.java | 3 ++- .../bitmessage/entity/payload/CryptoBox.java | 5 +++-- .../dissem/bitmessage/entity/payload/Msg.java | 3 ++- .../bitmessage/entity/payload/V4Pubkey.java | 3 ++- .../entity/valueobject/InventoryVector.java | 3 --- .../exception/DecryptionFailedException.java | 4 ++++ .../bitmessage/ports/NetworkHandler.java | 4 +++- .../ch/dissem/bitmessage/utils/Security.java | 12 +++++----- .../ch/dissem/bitmessage/EncryptionTest.java | 5 +++-- .../ch/dissem/bitmessage/SignatureTest.java | 13 +++-------- .../entity/BitmessageAddressTest.java | 3 ++- .../bitmessage/entity/SerializationTest.java | 3 ++- .../ch/dissem/bitmessage/utils/TestUtils.java | 3 ++- .../bitmessage/networking/Connection.java | 7 +++--- .../repository/JdbcAddressRepository.java | 12 +++++----- .../repository/JdbcMessageRepository.java | 22 +++++++++++++------ 22 files changed, 82 insertions(+), 73 deletions(-) create mode 100644 domain/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java diff --git a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java index f0aff97..2de6fa1 100644 --- a/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java +++ b/demo/src/main/java/ch/dissem/bitmessage/demo/Application.java @@ -206,7 +206,7 @@ public class Application { private void messages() { String command; - List messages = ctx.messages().findMessages(Plaintext.Status.RECEIVED); + List<Plaintext> messages = ctx.messages().findMessages(Plaintext.Status.NEW); do { System.out.println(); int i = 0; @@ -230,7 +230,7 @@ public class Application { return; default: try { - int index = Integer.parseInt(command); + int index = Integer.parseInt(command) - 1; show(messages.get(index)); } catch (NumberFormatException | IndexOutOfBoundsException e) { System.out.println("Unknown command. Please try again."); @@ -249,9 +249,9 @@ public class Application { System.out.println(); String command; do { - System.out.printf("r) reply"); + System.out.println("r) reply"); System.out.println("d) delete"); - System.out.printf("b) back"); + System.out.println("b) back"); command = nextCommand(); switch (command) { case "r": diff --git a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java index a592c4c..1d4d4fa 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/BitmessageContext.java @@ -142,11 +142,7 @@ public class BitmessageContext { } public void startup(Listener listener) { - MessageListener messageListener = new DefaultMessageListener(ctx, listener); - for (ObjectMessage object : ctx.getInventory().getObjects(0, 0, PUBKEY, MSG)) { - messageListener.receive(object); - } - ctx.getNetworkHandler().start(messageListener); + ctx.getNetworkHandler().start(new DefaultMessageListener(ctx, listener)); } public void shutdown() { diff --git a/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java index 81b7330..deeb8e4 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java +++ b/domain/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java @@ -20,6 +20,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.ports.NetworkHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +29,7 @@ import java.io.IOException; import java.util.List; import static ch.dissem.bitmessage.entity.Plaintext.Status.DOING_PROOF_OF_WORK; +import static ch.dissem.bitmessage.entity.Plaintext.Status.NEW; import static ch.dissem.bitmessage.entity.Plaintext.Status.SENT; import static ch.dissem.bitmessage.utils.UnixTime.DAY; @@ -42,7 +44,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { } @Override - public void receive(ObjectMessage object) { + public void receive(ObjectMessage object) throws IOException { ObjectPayload payload = object.getPayload(); if (payload.getType() == null) return; @@ -74,7 +76,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { } } - protected void receive(ObjectMessage object, Pubkey pubkey) { + protected void receive(ObjectMessage object, Pubkey pubkey) throws IOException { BitmessageAddress address; try { if (pubkey instanceof V4Pubkey) { @@ -106,26 +108,28 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { ctx.getMessageRepository().save(msg); } } - } catch (IllegalArgumentException | IOException e) { - LOG.debug(e.getMessage(), e); + } catch (DecryptionFailedException ignore) { + LOG.debug(ignore.getMessage(), ignore); } } - protected void receive(ObjectMessage object, Msg msg) { + protected void receive(ObjectMessage object, Msg msg) throws IOException { for (BitmessageAddress identity : ctx.getAddressRepo().getIdentities()) { try { msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey()); msg.getPlaintext().setTo(identity); object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey()); + msg.getPlaintext().setStatus(NEW); ctx.getMessageRepository().save(msg.getPlaintext()); listener.receive(msg.getPlaintext()); break; - } catch (IOException | RuntimeException ignore) { + } catch (DecryptionFailedException ignore) { + LOG.debug(ignore.getMessage(), ignore); } } } - protected void receive(ObjectMessage object, Broadcast broadcast) { + protected void receive(ObjectMessage object, Broadcast broadcast) throws IOException { // TODO this should work fine as-is, but checking the tag might be more efficient // V5Broadcast v5 = broadcast instanceof V5Broadcast ? (V5Broadcast) broadcast : null; for (BitmessageAddress subscription : ctx.getAddressRepo().getSubscriptions()) { @@ -133,7 +137,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener { broadcast.decrypt(subscription.getPubkeyDecryptionKey()); object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey()); listener.receive(broadcast.getPlaintext()); - } catch (IOException ignore) { + } catch (DecryptionFailedException ignore) { } } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java b/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java index 1e375a3..8b15371 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/Encrypted.java @@ -16,6 +16,8 @@ package ch.dissem.bitmessage.entity; +import ch.dissem.bitmessage.exception.DecryptionFailedException; + import java.io.IOException; /** @@ -24,7 +26,7 @@ import java.io.IOException; public interface Encrypted { void encrypt(byte[] publicKey) throws IOException; - void decrypt(byte[] privateKey) throws IOException; + void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException; boolean isDecrypted(); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java index 73ac107..4ccfcff 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java @@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.Bytes; import ch.dissem.bitmessage.utils.Encode; import ch.dissem.bitmessage.utils.Security; @@ -116,13 +117,13 @@ public class ObjectMessage implements MessagePayload { } } - public void decrypt(PrivateKey key) throws IOException { + public void decrypt(PrivateKey key) throws IOException, DecryptionFailedException { if (payload instanceof Encrypted) { ((Encrypted) payload).decrypt(key.getPrivateEncryptionKey()); } } - public void decrypt(byte[] privateEncryptionKey) throws IOException { + public void decrypt(byte[] privateEncryptionKey) throws IOException, DecryptionFailedException { if (payload instanceof Encrypted) { ((Encrypted) payload).decrypt(privateEncryptionKey); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java index c91f5f6..84e5bca 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java @@ -92,7 +92,7 @@ public class Plaintext implements Streamable { public void setTo(BitmessageAddress to) { if (this.to.getVersion() != 0) throw new RuntimeException("Correct address already set"); - if (Arrays.equals(this.to.getRipe(), to.getRipe())) { + if (!Arrays.equals(this.to.getRipe(), to.getRipe())) { throw new RuntimeException("RIPEs don't match"); } this.to = to; @@ -210,7 +210,7 @@ public class Plaintext implements Streamable { SENT_ACKNOWLEDGED, // For received messages - RECEIVED, + NEW, READ } @@ -348,9 +348,6 @@ public class Plaintext implements Streamable { } public Plaintext build() { - if (id == null) { - id = UUID.randomUUID(); - } if (from == null) { from = new BitmessageAddress(Factory.createPubkey( addressVersion, diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java index 0551ba5..0cbd0e4 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Broadcast.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity.payload; import ch.dissem.bitmessage.entity.Encrypted; import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import java.io.IOException; @@ -51,7 +52,7 @@ public abstract class Broadcast extends ObjectPayload implements Encrypted { } @Override - public void decrypt(byte[] privateKey) throws IOException { + public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException { plaintext = Plaintext.read(encrypted.decrypt(privateKey)); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java index d4cbfdb..8db2238 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/CryptoBox.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.entity.payload; import ch.dissem.bitmessage.entity.Streamable; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.*; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; @@ -99,7 +100,7 @@ public class CryptoBox implements Streamable { /** * @see <a href='https://bitmessage.org/wiki/Encryption#Decryption'>https://bitmessage.org/wiki/Encryption#Decryption</a> */ - public InputStream decrypt(byte[] privateKey) { + public InputStream decrypt(byte[] privateKey) throws DecryptionFailedException { // 1. The private key used to decrypt is called k. BigInteger k = Security.keyToBigInt(privateKey); // 2. Do an EC point multiply with private key k and public key R. This gives you public key P. @@ -113,7 +114,7 @@ public class CryptoBox implements Streamable { // 5. Calculate MAC' with HMACSHA256, using key_m as salt and IV + R + cipher text as data. // 6. Compare MAC with MAC'. If not equal, decryption will fail. if (!Arrays.equals(mac, calculateMac(key_m))) { - throw new RuntimeException("Invalid MAC while decrypting"); + throw new DecryptionFailedException(); } // 7. Decrypt the cipher text with AES-256-CBC, using IV as initialization vector, key_e as decryption key diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java index b94cb2b..88026c8 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/Msg.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity.payload; import ch.dissem.bitmessage.entity.Encrypted; import ch.dissem.bitmessage.entity.Plaintext; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import java.io.IOException; import java.io.InputStream; @@ -85,7 +86,7 @@ public class Msg extends ObjectPayload implements Encrypted { } @Override - public void decrypt(byte[] privateKey) throws IOException { + public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException { plaintext = Plaintext.read(encrypted.decrypt(privateKey)); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java index 1b2f579..e6ec264 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/payload/V4Pubkey.java @@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity.payload; import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.Encrypted; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.Decode; import java.io.IOException; @@ -65,7 +66,7 @@ public class V4Pubkey extends Pubkey implements Encrypted { } @Override - public void decrypt(byte[] privateKey) throws IOException { + public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException { decrypted = V3Pubkey.read(encrypted.decrypt(privateKey), stream); } diff --git a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java b/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java index 48667e5..366d26b 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java +++ b/domain/src/main/java/ch/dissem/bitmessage/entity/valueobject/InventoryVector.java @@ -23,9 +23,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; -/** - * Created by chris on 13.03.15. - */ public class InventoryVector implements Streamable { /** * Hash of the object diff --git a/domain/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java b/domain/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java new file mode 100644 index 0000000..05417da --- /dev/null +++ b/domain/src/main/java/ch/dissem/bitmessage/exception/DecryptionFailedException.java @@ -0,0 +1,4 @@ +package ch.dissem.bitmessage.exception; + +public class DecryptionFailedException extends Exception { +} diff --git a/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java b/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java index 5266755..1d37df9 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java +++ b/domain/src/main/java/ch/dissem/bitmessage/ports/NetworkHandler.java @@ -21,6 +21,8 @@ import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.ObjectPayload; import ch.dissem.bitmessage.entity.valueobject.InventoryVector; +import java.io.IOException; + /** * Handles incoming messages */ @@ -32,6 +34,6 @@ public interface NetworkHandler { void offer(InventoryVector iv); interface MessageListener { - void receive(ObjectMessage object); + void receive(ObjectMessage object) throws IOException; } } diff --git a/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java b/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java index 6364753..978be35 100644 --- a/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java +++ b/domain/src/main/java/ch/dissem/bitmessage/utils/Security.java @@ -17,7 +17,7 @@ package ch.dissem.bitmessage.utils; import ch.dissem.bitmessage.entity.ObjectMessage; -import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.ports.ProofOfWorkEngine; import org.bouncycastle.asn1.x9.X9ECParameters; @@ -35,7 +35,6 @@ import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.math.BigInteger; import java.security.*; -import java.security.PrivateKey; import java.security.spec.KeySpec; import java.util.Arrays; @@ -110,11 +109,10 @@ public class Security { * @throws IOException if proof of work doesn't check out */ public static void checkProofOfWork(ObjectMessage object, long nonceTrialsPerByte, long extraBytes) throws IOException { - if (Bytes.lt( - getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes), - Security.doubleSha512(object.getNonce(), getInitialHash(object)), - 8)) { - throw new IOException("Insufficient proof of work"); + byte[] target = getProofOfWorkTarget(object, nonceTrialsPerByte, extraBytes); + byte[] value = Security.doubleSha512(object.getNonce(), getInitialHash(object)); + if (Bytes.lt(target, value, 8)) { + throw new IOException("Insufficient proof of work: " + Strings.hex(target) + " required, " + Strings.hex(Arrays.copyOfRange(value, 0, 8)) + " achieved."); } } diff --git a/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java b/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java index 038d528..ecaf2b1 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/EncryptionTest.java @@ -23,6 +23,7 @@ import ch.dissem.bitmessage.entity.payload.CryptoBox; import ch.dissem.bitmessage.entity.payload.GenericPayload; import ch.dissem.bitmessage.entity.payload.Msg; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.Security; import ch.dissem.bitmessage.utils.TestUtils; import org.junit.Test; @@ -35,7 +36,7 @@ import static org.junit.Assert.assertTrue; public class EncryptionTest { @Test - public void ensureDecryptedDataIsSameAsBeforeEncryption() throws IOException { + public void ensureDecryptedDataIsSameAsBeforeEncryption() throws IOException, DecryptionFailedException { GenericPayload before = new GenericPayload(1, Security.randomBytes(100)); PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000); @@ -47,7 +48,7 @@ public class EncryptionTest { } @Test - public void ensureMessageCanBeDecrypted() throws IOException { + public void ensureMessageCanBeDecrypted() throws IOException, DecryptionFailedException { PrivateKey privateKey = PrivateKey.read(TestUtils.getResource("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey")); BitmessageAddress identity = new BitmessageAddress(privateKey); assertEquals("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8", identity.getAddress()); diff --git a/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java b/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java index 6b3a02f..4f733fc 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/SignatureTest.java @@ -24,6 +24,7 @@ import ch.dissem.bitmessage.entity.payload.ObjectType; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.TestUtils; import org.junit.Test; @@ -56,23 +57,15 @@ public class SignatureTest { } @Test - public void ensureMessageIsProperlySigned() throws IOException { + public void ensureMessageIsProperlySigned() throws IOException, DecryptionFailedException { BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"); ObjectMessage object = TestUtils.loadObjectMessage(3, "V1Msg.payload"); Msg msg = (Msg) object.getPayload(); msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey()); Plaintext plaintext = msg.getPlaintext(); - assertEquals(0, object.getExpiresTime()); - assertEquals(loadPubkey(), plaintext.getFrom().getPubkey()); + assertEquals(TestUtils.loadContact().getPubkey(), plaintext.getFrom().getPubkey()); assertNotNull(plaintext); assertTrue(object.isSignatureValid(plaintext.getFrom().getPubkey())); } - - private V4Pubkey loadPubkey() throws IOException { - BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"); - ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload"); - object.decrypt(address.getPubkeyDecryptionKey()); - return (V4Pubkey) object.getPayload(); - } } diff --git a/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java b/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java index f208b44..44357c4 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/entity/BitmessageAddressTest.java @@ -19,6 +19,7 @@ package ch.dissem.bitmessage.entity; import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.utils.*; import org.junit.Test; @@ -80,7 +81,7 @@ public class BitmessageAddressTest { } @Test - public void testV4PubkeyImport() throws IOException { + public void testV4PubkeyImport() throws IOException, DecryptionFailedException { BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"); ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload"); object.decrypt(address.getPubkeyDecryptionKey()); diff --git a/domain/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java b/domain/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java index a2fa39d..9817271 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java +++ b/domain/src/test/java/ch/dissem/bitmessage/entity/SerializationTest.java @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.entity; import ch.dissem.bitmessage.entity.payload.*; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.factory.Factory; import ch.dissem.bitmessage.utils.TestUtils; import org.junit.Test; @@ -76,7 +77,7 @@ public class SerializationTest { } @Test - public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException { + public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException { Plaintext p1 = new Plaintext.Builder() .from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")) .to(TestUtils.loadContact()) diff --git a/domain/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java b/domain/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java index 12f77be..73ac939 100644 --- a/domain/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java +++ b/domain/src/test/java/ch/dissem/bitmessage/utils/TestUtils.java @@ -20,6 +20,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.ObjectMessage; import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey; +import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.factory.Factory; import java.io.ByteArrayInputStream; @@ -68,7 +69,7 @@ public class TestUtils { return identity; } - public static BitmessageAddress loadContact() throws IOException { + public static BitmessageAddress loadContact() throws IOException, DecryptionFailedException { BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"); ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload"); object.decrypt(address.getPubkeyDecryptionKey()); diff --git a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java index 7bc356c..0cab994 100644 --- a/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java +++ b/networking/src/main/java/ch/dissem/bitmessage/networking/Connection.java @@ -121,7 +121,7 @@ public class Connection implements Runnable { + msg.getPayload().getCommand()); } } - } catch (SocketTimeoutException e) { + } catch (SocketTimeoutException ignore) { if (state == ACTIVE) { sendQueue(); } @@ -157,12 +157,11 @@ public class Connection implements Runnable { try { LOG.debug("Received object " + objectMessage.getInventoryVector()); Security.checkProofOfWork(objectMessage, ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes()); + listener.receive(objectMessage); ctx.getInventory().storeObject(objectMessage); } catch (IOException e) { - LOG.debug(e.getMessage(), e); + LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e); } - // It's probably pointless, but let the listener decide if we accept the message for the client. - listener.receive(objectMessage); break; case ADDR: Addr addr = (Addr) messagePayload; 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 3efdec3..413d468 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcAddressRepository.java @@ -96,7 +96,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito if (publicKeyBlob != null) { Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(), publicKeyBlob.getBinaryStream(), (int) publicKeyBlob.length(), false); - if (address.getVersion() == 4) { + if (address.getVersion() == 4 && pubkey instanceof V3Pubkey) { pubkey = new V4Pubkey((V3Pubkey) pubkey); } address.setPubkey(pubkey); @@ -140,11 +140,11 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito private void update(BitmessageAddress address) throws IOException, SQLException { PreparedStatement ps = getConnection().prepareStatement( - "UPDATE Address SET address=?, alias=?, public_key=?, private_key=?"); - ps.setString(1, address.getAddress()); - ps.setString(2, address.getAlias()); - writePubkey(ps, 3, address.getPubkey()); - writeBlob(ps, 4, address.getPrivateKey()); + "UPDATE Address SET alias=?, public_key=?, private_key=? WHERE address=?"); + ps.setString(1, address.getAlias()); + writePubkey(ps, 2, address.getPubkey()); + writeBlob(ps, 3, address.getPrivateKey()); + ps.setString(4, address.getAddress()); ps.executeUpdate(); } diff --git a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java index 3c9aeea..1777d2c 100644 --- a/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java +++ b/repositories/src/main/java/ch/dissem/bitmessage/repository/JdbcMessageRepository.java @@ -53,7 +53,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito @Override public List<Plaintext> findMessages(Label label) { - return find("id IN SELECT message_id FROM Message_Label WHERE label_id=" + label.getId()); + return find("id IN (SELECT message_id FROM Message_Label WHERE label_id=" + label.getId() + ")"); } @Override @@ -94,7 +94,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito List<Label> result = new ArrayList<>(); try { Statement stmt = getConnection().createStatement(); - ResultSet rs = stmt.executeQuery("SELECT label, color FROM Label WHERE id IN SELECT label_id FROM Message_Label WHERE message_id=" + messageId); + ResultSet rs = stmt.executeQuery("SELECT label, color FROM Label WHERE id IN (SELECT label_id FROM Message_Label WHERE message_id=" + messageId + ")"); while (rs.next()) { result.add(new Label(rs.getString("label"), rs.getInt("color"))); } @@ -109,8 +109,8 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito // save from address if necessary if (message.getId() == null) { BitmessageAddress savedAddress = ctx.getAddressRepo().getAddress(message.getFrom().getAddress()); - if (savedAddress.getPrivateKey() == null) { - if (savedAddress.getAlias() != null) { + if (savedAddress == null || savedAddress.getPrivateKey() == null) { + if (savedAddress != null && savedAddress.getAlias() != null) { message.getFrom().setAlias(savedAddress.getAlias()); } ctx.getAddressRepo().save(message.getFrom()); @@ -157,7 +157,11 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito writeBlob(ps, 3, message); ps.setLong(4, message.getSent()); ps.setLong(5, message.getReceived()); - ps.setString(6, message.getStatus().name()); + if (message.getStatus() != null) + ps.setString(6, message.getStatus().name()); + else + ps.setString(6, null); + ps.executeUpdate(); // get generated id @@ -168,10 +172,14 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito private void update(Connection connection, Plaintext message) throws SQLException, IOException { PreparedStatement ps = connection.prepareStatement( - "UPDATE Message SET sent=?, received=?, status=?"); + "UPDATE Message SET sent=?, received=?, status=? WHERE id=?"); ps.setLong(1, message.getSent()); ps.setLong(2, message.getReceived()); - ps.setString(3, message.getStatus().name()); + ps.setLong(3, (Long) message.getId()); + if (message.getStatus() != null) + ps.setString(3, message.getStatus().name()); + else + ps.setString(3, null); ps.executeUpdate(); }