Merge branch 'release/1.0.1'
This commit is contained in:
		| @@ -5,7 +5,7 @@ subprojects { | |||||||
|  |  | ||||||
|     sourceCompatibility = 1.7 |     sourceCompatibility = 1.7 | ||||||
|     group = 'ch.dissem.jabit' |     group = 'ch.dissem.jabit' | ||||||
|     version = '1.0.0' |     version = '1.0.1' | ||||||
|  |  | ||||||
|     ext.isReleaseVersion = !version.endsWith("SNAPSHOT") |     ext.isReleaseVersion = !version.endsWith("SNAPSHOT") | ||||||
|  |  | ||||||
| @@ -34,7 +34,7 @@ subprojects { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     signing { |     signing { | ||||||
|         required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } |         required { isReleaseVersion && project.getProperties().get("signing.keyId")?.length() > 0 } | ||||||
|         sign configurations.archives |         sign configurations.archives | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,20 +17,22 @@ | |||||||
| package ch.dissem.bitmessage; | package ch.dissem.bitmessage; | ||||||
|  |  | ||||||
| import ch.dissem.bitmessage.entity.*; | 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.payload.Pubkey.Feature; | ||||||
| import ch.dissem.bitmessage.entity.valueobject.InventoryVector; | import ch.dissem.bitmessage.entity.valueobject.InventoryVector; | ||||||
| import ch.dissem.bitmessage.entity.valueobject.Label; | import ch.dissem.bitmessage.entity.valueobject.Label; | ||||||
| import ch.dissem.bitmessage.entity.valueobject.PrivateKey; | import ch.dissem.bitmessage.entity.valueobject.PrivateKey; | ||||||
| import ch.dissem.bitmessage.exception.DecryptionFailedException; | import ch.dissem.bitmessage.exception.DecryptionFailedException; | ||||||
| import ch.dissem.bitmessage.factory.Factory; |  | ||||||
| import ch.dissem.bitmessage.ports.*; | import ch.dissem.bitmessage.ports.*; | ||||||
| import ch.dissem.bitmessage.utils.Property; | import ch.dissem.bitmessage.utils.Property; | ||||||
|  | import ch.dissem.bitmessage.utils.TTL; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| import java.net.InetAddress; | import java.net.InetAddress; | ||||||
| import java.util.Arrays; |  | ||||||
| import java.util.Timer; | import java.util.Timer; | ||||||
| import java.util.TimerTask; | import java.util.TimerTask; | ||||||
| import java.util.concurrent.*; | import java.util.concurrent.*; | ||||||
| @@ -38,9 +40,7 @@ import java.util.concurrent.*; | |||||||
| import static ch.dissem.bitmessage.entity.Plaintext.Status.*; | 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.BROADCAST; | ||||||
| import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; | import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG; | ||||||
| import static ch.dissem.bitmessage.utils.UnixTime.DAY; | import static ch.dissem.bitmessage.utils.UnixTime.*; | ||||||
| import static ch.dissem.bitmessage.utils.UnixTime.HOUR; |  | ||||||
| import static ch.dissem.bitmessage.utils.UnixTime.MINUTE; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * <p>Use this class if you want to create a Bitmessage client.</p> |  * <p>Use this class if you want to create a Bitmessage client.</p> | ||||||
| @@ -122,67 +122,24 @@ public class BitmessageContext { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void broadcast(final BitmessageAddress from, final String subject, final String message) { |     public void broadcast(final BitmessageAddress from, final String subject, final String message) { | ||||||
|         pool.submit(new Runnable() { |         Plaintext msg = new Plaintext.Builder(BROADCAST) | ||||||
|             @Override |                 .from(from) | ||||||
|             public void run() { |                 .message(subject, message) | ||||||
|                 Plaintext msg = new Plaintext.Builder(BROADCAST) |                 .build(); | ||||||
|                         .from(from) |         send(msg); | ||||||
|                         .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); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void send(final BitmessageAddress from, final BitmessageAddress to, final String subject, final String message) { |     public void send(final BitmessageAddress from, final BitmessageAddress to, final String subject, final String message) { | ||||||
|         if (from.getPrivateKey() == null) { |         if (from.getPrivateKey() == null) { | ||||||
|             throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key."); |             throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key."); | ||||||
|         } |         } | ||||||
|         pool.submit(new Runnable() { |         Plaintext msg = new Plaintext.Builder(MSG) | ||||||
|             @Override |                 .from(from) | ||||||
|             public void run() { |                 .to(to) | ||||||
|                 Plaintext msg = new Plaintext.Builder(MSG) |                 .message(subject, message) | ||||||
|                         .from(from) |                 .labels(messages().getLabels(Label.Type.SENT)) | ||||||
|                         .to(to) |                 .build(); | ||||||
|                         .message(subject, message) |         send(msg); | ||||||
|                         .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); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void send(final Plaintext msg) { |     public void send(final Plaintext msg) { | ||||||
| @@ -193,15 +150,18 @@ public class BitmessageContext { | |||||||
|             @Override |             @Override | ||||||
|             public void run() { |             public void run() { | ||||||
|                 BitmessageAddress to = msg.getTo(); |                 BitmessageAddress to = msg.getTo(); | ||||||
|                 if (to.getPubkey() == null) { |                 if (to != null) { | ||||||
|                     tryToFindMatchingPubkey(to); |                     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) { |                 if (to == null || to.getPubkey() != null) { | ||||||
|                     LOG.info("Public key is missing from recipient. Requesting."); |  | ||||||
|                     requestPubkey(msg.getFrom(), to); |  | ||||||
|                     msg.setStatus(PUBKEY_REQUESTED); |  | ||||||
|                     ctx.getMessageRepository().save(msg); |  | ||||||
|                 } else { |  | ||||||
|                     LOG.info("Sending message."); |                     LOG.info("Sending message."); | ||||||
|                     msg.setStatus(DOING_PROOF_OF_WORK); |                     msg.setStatus(DOING_PROOF_OF_WORK); | ||||||
|                     ctx.getMessageRepository().save(msg); |                     ctx.getMessageRepository().save(msg); | ||||||
| @@ -209,7 +169,7 @@ public class BitmessageContext { | |||||||
|                             msg.getFrom(), |                             msg.getFrom(), | ||||||
|                             to, |                             to, | ||||||
|                             new Msg(msg), |                             new Msg(msg), | ||||||
|                             +2 * DAY |                             TTL.msg() | ||||||
|                     ); |                     ); | ||||||
|                     msg.setStatus(SENT); |                     msg.setStatus(SENT); | ||||||
|                     msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); |                     msg.addLabels(ctx.getMessageRepository().getLabels(Label.Type.SENT)); | ||||||
| @@ -219,15 +179,6 @@ public class BitmessageContext { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void requestPubkey(BitmessageAddress requestingIdentity, BitmessageAddress address) { |  | ||||||
|         ctx.send( |  | ||||||
|                 requestingIdentity, |  | ||||||
|                 address, |  | ||||||
|                 new GetPubkey(address), |  | ||||||
|                 +28 * DAY |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void startup() { |     public void startup() { | ||||||
|         ctx.getNetworkHandler().start(networkListener); |         ctx.getNetworkHandler().start(networkListener); | ||||||
|     } |     } | ||||||
| @@ -280,41 +231,11 @@ public class BitmessageContext { | |||||||
|  |  | ||||||
|     public void addContact(BitmessageAddress contact) { |     public void addContact(BitmessageAddress contact) { | ||||||
|         ctx.getAddressRepository().save(contact); |         ctx.getAddressRepository().save(contact); | ||||||
|         tryToFindMatchingPubkey(contact); |  | ||||||
|         if (contact.getPubkey() == null) { |         if (contact.getPubkey() == null) { | ||||||
|             ctx.requestPubkey(contact); |             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) { |     public void addSubscribtion(BitmessageAddress address) { | ||||||
|         address.setSubscribed(true); |         address.setSubscribed(true); | ||||||
|         ctx.getAddressRepository().save(address); |         ctx.getAddressRepository().save(address); | ||||||
| @@ -368,7 +289,6 @@ public class BitmessageContext { | |||||||
|         int connectionLimit = 150; |         int connectionLimit = 150; | ||||||
|         long connectionTTL = 30 * MINUTE; |         long connectionTTL = 30 * MINUTE; | ||||||
|         boolean sendPubkeyOnIdentityCreation = true; |         boolean sendPubkeyOnIdentityCreation = true; | ||||||
|         long pubkeyTTL = 28; |  | ||||||
|  |  | ||||||
|         public Builder() { |         public Builder() { | ||||||
|         } |         } | ||||||
| @@ -463,7 +383,7 @@ public class BitmessageContext { | |||||||
|          */ |          */ | ||||||
|         public Builder pubkeyTTL(long days) { |         public Builder pubkeyTTL(long days) { | ||||||
|             if (days < 0 || days > 28 * DAY) throw new IllegalArgumentException("TTL must be between 1 and 28 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; |             return this; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,16 +19,16 @@ package ch.dissem.bitmessage; | |||||||
| import ch.dissem.bitmessage.entity.BitmessageAddress; | import ch.dissem.bitmessage.entity.BitmessageAddress; | ||||||
| import ch.dissem.bitmessage.entity.Encrypted; | import ch.dissem.bitmessage.entity.Encrypted; | ||||||
| import ch.dissem.bitmessage.entity.ObjectMessage; | import ch.dissem.bitmessage.entity.ObjectMessage; | ||||||
| import ch.dissem.bitmessage.entity.payload.Broadcast; | import ch.dissem.bitmessage.entity.payload.*; | ||||||
| import ch.dissem.bitmessage.entity.payload.GetPubkey; |  | ||||||
| import ch.dissem.bitmessage.entity.payload.ObjectPayload; |  | ||||||
| import ch.dissem.bitmessage.ports.*; | import ch.dissem.bitmessage.ports.*; | ||||||
| import ch.dissem.bitmessage.utils.Singleton; | import ch.dissem.bitmessage.utils.Singleton; | ||||||
|  | import ch.dissem.bitmessage.utils.TTL; | ||||||
| import ch.dissem.bitmessage.utils.UnixTime; | import ch.dissem.bitmessage.utils.UnixTime; | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.util.Arrays; | ||||||
| import java.util.TreeSet; | import java.util.TreeSet; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -59,7 +59,6 @@ public class InternalContext { | |||||||
|     private final long clientNonce; |     private final long clientNonce; | ||||||
|     private final long networkNonceTrialsPerByte = 1000; |     private final long networkNonceTrialsPerByte = 1000; | ||||||
|     private final long networkExtraBytes = 1000; |     private final long networkExtraBytes = 1000; | ||||||
|     private final long pubkeyTTL; |  | ||||||
|     private long connectionTTL; |     private long connectionTTL; | ||||||
|     private int connectionLimit; |     private int connectionLimit; | ||||||
|  |  | ||||||
| @@ -79,7 +78,6 @@ public class InternalContext { | |||||||
|         this.port = builder.port; |         this.port = builder.port; | ||||||
|         this.connectionLimit = builder.connectionLimit; |         this.connectionLimit = builder.connectionLimit; | ||||||
|         this.connectionTTL = builder.connectionTTL; |         this.connectionTTL = builder.connectionTTL; | ||||||
|         this.pubkeyTTL = builder.pubkeyTTL; |  | ||||||
|  |  | ||||||
|         Singleton.initialize(cryptography); |         Singleton.initialize(cryptography); | ||||||
|  |  | ||||||
| @@ -195,7 +193,7 @@ public class InternalContext { | |||||||
|  |  | ||||||
|     public void sendPubkey(final BitmessageAddress identity, final long targetStream) { |     public void sendPubkey(final BitmessageAddress identity, final long targetStream) { | ||||||
|         try { |         try { | ||||||
|             long expires = UnixTime.now(pubkeyTTL); |             long expires = UnixTime.now(TTL.pubkey()); | ||||||
|             LOG.info("Expires at " + expires); |             LOG.info("Expires at " + expires); | ||||||
|             final ObjectMessage response = new ObjectMessage.Builder() |             final ObjectMessage response = new ObjectMessage.Builder() | ||||||
|                     .stream(targetStream) |                     .stream(targetStream) | ||||||
| @@ -212,16 +210,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) { |     public void requestPubkey(final BitmessageAddress contact) { | ||||||
|         long expires = UnixTime.now(+pubkeyTTL); |         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(TTL.getpubkey()); | ||||||
|         LOG.info("Expires at " + expires); |         LOG.info("Expires at " + expires); | ||||||
|         final ObjectMessage response = new ObjectMessage.Builder() |         final ObjectMessage request = new ObjectMessage.Builder() | ||||||
|                 .stream(contact.getStream()) |                 .stream(contact.getStream()) | ||||||
|                 .expiresTime(expires) |                 .expiresTime(expires) | ||||||
|                 .payload(new GetPubkey(contact)) |                 .payload(new GetPubkey(contact)) | ||||||
|                 .build(); |                 .build(); | ||||||
|         messageCallback.proofOfWorkStarted(response.getPayload()); |         messageCallback.proofOfWorkStarted(request.getPayload()); | ||||||
|         proofOfWorkService.doProofOfWork(response); |         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() { |     public long getClientNonce() { | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import ch.dissem.bitmessage.entity.BitmessageAddress; | |||||||
| import ch.dissem.bitmessage.entity.ObjectMessage; | import ch.dissem.bitmessage.entity.ObjectMessage; | ||||||
| import ch.dissem.bitmessage.entity.Plaintext; | import ch.dissem.bitmessage.entity.Plaintext; | ||||||
| import ch.dissem.bitmessage.entity.PlaintextHolder; | import ch.dissem.bitmessage.entity.PlaintextHolder; | ||||||
|  | import ch.dissem.bitmessage.entity.payload.Pubkey; | ||||||
| import ch.dissem.bitmessage.ports.MessageRepository; | import ch.dissem.bitmessage.ports.MessageRepository; | ||||||
| import ch.dissem.bitmessage.ports.ProofOfWorkEngine; | import ch.dissem.bitmessage.ports.ProofOfWorkEngine; | ||||||
| import ch.dissem.bitmessage.ports.ProofOfWorkRepository; | import ch.dissem.bitmessage.ports.ProofOfWorkRepository; | ||||||
| @@ -42,10 +43,10 @@ public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalC | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { |     public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) { | ||||||
|         long nonceTrialsPerByte = recipient == null ? |         Pubkey pubkey = recipient == null ? null : recipient.getPubkey(); | ||||||
|                 ctx.getNetworkNonceTrialsPerByte() : recipient.getPubkey().getNonceTrialsPerByte(); |  | ||||||
|         long extraBytes = recipient == null ? |         long nonceTrialsPerByte = pubkey == null ? ctx.getNetworkNonceTrialsPerByte() : pubkey.getNonceTrialsPerByte(); | ||||||
|                 ctx.getNetworkExtraBytes() : recipient.getPubkey().getExtraBytes(); |         long extraBytes = pubkey == null ? ctx.getNetworkExtraBytes() : pubkey.getExtraBytes(); | ||||||
|  |  | ||||||
|         powRepo.putObject(object, nonceTrialsPerByte, extraBytes); |         powRepo.putObject(object, nonceTrialsPerByte, extraBytes); | ||||||
|         if (object.getPayload() instanceof PlaintextHolder) { |         if (object.getPayload() instanceof PlaintextHolder) { | ||||||
|   | |||||||
| @@ -79,6 +79,7 @@ public class Label implements Serializable { | |||||||
|         INBOX, |         INBOX, | ||||||
|         BROADCAST, |         BROADCAST, | ||||||
|         DRAFT, |         DRAFT, | ||||||
|  |         OUTBOX, | ||||||
|         SENT, |         SENT, | ||||||
|         UNREAD, |         UNREAD, | ||||||
|         TRASH |         TRASH | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package ch.dissem.bitmessage.utils; | package ch.dissem.bitmessage.utils; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Created by chrig on 07.12.2015. |  * @author Christian Basler | ||||||
|  */ |  */ | ||||||
| public class Numbers { | public class Numbers { | ||||||
|     public static long max(long a, long b) { |     public static long max(long a, long b) { | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								core/src/main/java/ch/dissem/bitmessage/utils/TTL.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								core/src/main/java/ch/dissem/bitmessage/utils/TTL.java
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,11 +1,11 @@ | |||||||
| package ch.dissem.bitmessage.security; | package ch.dissem.bitmessage.security; | ||||||
|  |  | ||||||
| import ch.dissem.bitmessage.InternalContext; | import ch.dissem.bitmessage.InternalContext; | ||||||
|  | import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; | ||||||
| import ch.dissem.bitmessage.entity.ObjectMessage; | import ch.dissem.bitmessage.entity.ObjectMessage; | ||||||
| import ch.dissem.bitmessage.entity.payload.GenericPayload; | import ch.dissem.bitmessage.entity.payload.GenericPayload; | ||||||
| import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; | import ch.dissem.bitmessage.ports.MultiThreadedPOWEngine; | ||||||
| import ch.dissem.bitmessage.ports.ProofOfWorkEngine; | import ch.dissem.bitmessage.ports.ProofOfWorkEngine; | ||||||
| import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography; |  | ||||||
| import ch.dissem.bitmessage.utils.CallbackWaiter; | import ch.dissem.bitmessage.utils.CallbackWaiter; | ||||||
| import ch.dissem.bitmessage.utils.Singleton; | import ch.dissem.bitmessage.utils.Singleton; | ||||||
| import ch.dissem.bitmessage.utils.UnixTime; | import ch.dissem.bitmessage.utils.UnixTime; | ||||||
| @@ -15,13 +15,13 @@ import javax.xml.bind.DatatypeConverter; | |||||||
| import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||||
| import java.io.IOException; | 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.junit.Assert.assertArrayEquals; | ||||||
| import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||||
| import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Created by chris on 19.07.15. |  * @author Christian Basler | ||||||
|  */ |  */ | ||||||
| public class CryptographyTest { | public class CryptographyTest { | ||||||
|     public static final byte[] TEST_VALUE = "teststring".getBytes(); |     public static final byte[] TEST_VALUE = "teststring".getBytes(); | ||||||
| @@ -72,7 +72,7 @@ public class CryptographyTest { | |||||||
|     public void testProofOfWorkFails() throws IOException { |     public void testProofOfWorkFails() throws IOException { | ||||||
|         ObjectMessage objectMessage = new ObjectMessage.Builder() |         ObjectMessage objectMessage = new ObjectMessage.Builder() | ||||||
|                 .nonce(new byte[8]) |                 .nonce(new byte[8]) | ||||||
|                 .expiresTime(UnixTime.now(+2 * DAY)) // 5 minutes |                 .expiresTime(UnixTime.now(+2 * MINUTE)) | ||||||
|                 .objectType(0) |                 .objectType(0) | ||||||
|                 .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) |                 .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) | ||||||
|                 .build(); |                 .build(); | ||||||
| @@ -83,7 +83,7 @@ public class CryptographyTest { | |||||||
|     public void testDoProofOfWork() throws Exception { |     public void testDoProofOfWork() throws Exception { | ||||||
|         ObjectMessage objectMessage = new ObjectMessage.Builder() |         ObjectMessage objectMessage = new ObjectMessage.Builder() | ||||||
|                 .nonce(new byte[8]) |                 .nonce(new byte[8]) | ||||||
|                 .expiresTime(UnixTime.now(+2 * DAY)) |                 .expiresTime(UnixTime.now(+2 * MINUTE)) | ||||||
|                 .objectType(0) |                 .objectType(0) | ||||||
|                 .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) |                 .payload(GenericPayload.read(0, new ByteArrayInputStream(new byte[0]), 1, 0)) | ||||||
|                 .build(); |                 .build(); | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ uploadArchives { | |||||||
|  |  | ||||||
| sourceCompatibility = 1.8 | sourceCompatibility = 1.8 | ||||||
|  |  | ||||||
|  | test.enabled = Boolean.valueOf(systemTestsEnabled) | ||||||
|  |  | ||||||
| task fatCapsule(type: FatCapsule) { | task fatCapsule(type: FatCapsule) { | ||||||
|     applicationClass 'ch.dissem.bitmessage.demo.Main' |     applicationClass 'ch.dissem.bitmessage.demo.Main' | ||||||
| } | } | ||||||
| @@ -30,4 +32,5 @@ dependencies { | |||||||
|     compile 'args4j:args4j:2.32' |     compile 'args4j:args4j:2.32' | ||||||
|     compile 'com.h2database:h2:1.4.190' |     compile 'com.h2database:h2:1.4.190' | ||||||
|     testCompile 'junit:junit:4.11' |     testCompile 'junit:junit:4.11' | ||||||
|  |     testCompile 'org.mockito:mockito-core:1.10.19' | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										84
									
								
								demo/src/test/java/ch/dissem/bitmessage/SystemTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								demo/src/test/java/ch/dissem/bitmessage/SystemTest.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | |||||||
|  | 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 ch.dissem.bitmessage.utils.TTL; | ||||||
|  | import org.junit.AfterClass; | ||||||
|  | import org.junit.BeforeClass; | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @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() { | ||||||
|  |         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)) | ||||||
|  |                 .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(15, TimeUnit.MINUTES); | ||||||
|  |  | ||||||
|  |         assertThat(plaintext.getText(), equalTo(originalMessage)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								demo/src/test/java/ch/dissem/bitmessage/TestListener.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								demo/src/test/java/ch/dissem/bitmessage/TestListener.java
									
									
									
									
									
										Normal file
									
								
							| @@ -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<Plaintext> 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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -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 | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -8,3 +8,4 @@ signing.password= | |||||||
| ossrhUsername= | ossrhUsername= | ||||||
| ossrhPassword= | ossrhPassword= | ||||||
|  |  | ||||||
|  | systemTestsEnabled=false | ||||||
| @@ -152,13 +152,25 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito | |||||||
|  |  | ||||||
|     private void update(BitmessageAddress address) throws IOException, SQLException { |     private void update(BitmessageAddress address) throws IOException, SQLException { | ||||||
|         try (Connection connection = config.getConnection()) { |         try (Connection connection = config.getConnection()) { | ||||||
|             PreparedStatement ps = connection.prepareStatement( |             StringBuilder statement = new StringBuilder("UPDATE Address SET alias=?"); | ||||||
|                     "UPDATE Address SET alias=?, public_key=?, private_key=?, subscribed=? WHERE address=?"); |             if (address.getPubkey() != null) { | ||||||
|             ps.setString(1, address.getAlias()); |                 statement.append(", public_key=?"); | ||||||
|             writePubkey(ps, 2, address.getPubkey()); |             } | ||||||
|             writeBlob(ps, 3, address.getPrivateKey()); |             if (address.getPrivateKey() != null) { | ||||||
|             ps.setBoolean(4, address.isSubscribed()); |                 statement.append(", private_key=?"); | ||||||
|             ps.setString(5, address.getAddress()); |             } | ||||||
|  |             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(); |             ps.executeUpdate(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -128,6 +128,17 @@ public class JdbcAddressRepositoryTest extends TestBase { | |||||||
|         assertEquals("Test-Alias", address.getAlias()); |         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 |     @Test | ||||||
|     public void testRemove() throws Exception { |     public void testRemove() throws Exception { | ||||||
|         BitmessageAddress address = repo.getAddress(IDENTITY_A); |         BitmessageAddress address = repo.getAddress(IDENTITY_A); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user