Merge branch 'release/1.0.1'
This commit is contained in:
commit
d580d6983b
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user