Broadcasts. Receiving seems to work, but there still seems to be a problem with sending them.
This commit is contained in:
parent
f76864eebd
commit
b4683bba68
@ -22,9 +22,6 @@ import ch.dissem.bitmessage.entity.Plaintext;
|
|||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
import ch.dissem.bitmessage.networking.NetworkNode;
|
import ch.dissem.bitmessage.networking.NetworkNode;
|
||||||
import ch.dissem.bitmessage.repository.*;
|
import ch.dissem.bitmessage.repository.*;
|
||||||
import ch.dissem.bitmessage.utils.Strings;
|
|
||||||
import org.flywaydb.core.internal.util.logging.slf4j.Slf4jLog;
|
|
||||||
import org.flywaydb.core.internal.util.logging.slf4j.Slf4jLogCreator;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -72,6 +69,7 @@ public class Application {
|
|||||||
System.out.println("available commands:");
|
System.out.println("available commands:");
|
||||||
System.out.println("i) identities");
|
System.out.println("i) identities");
|
||||||
System.out.println("c) contacts");
|
System.out.println("c) contacts");
|
||||||
|
System.out.println("s) subscriptions");
|
||||||
System.out.println("m) messages");
|
System.out.println("m) messages");
|
||||||
System.out.println("e) exit");
|
System.out.println("e) exit");
|
||||||
|
|
||||||
@ -85,6 +83,9 @@ public class Application {
|
|||||||
case "c":
|
case "c":
|
||||||
contacts();
|
contacts();
|
||||||
break;
|
break;
|
||||||
|
case "s":
|
||||||
|
subscriptions();
|
||||||
|
break;
|
||||||
case "m":
|
case "m":
|
||||||
messages();
|
messages();
|
||||||
break;
|
break;
|
||||||
@ -181,7 +182,7 @@ public class Application {
|
|||||||
command = nextCommand();
|
command = nextCommand();
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "a":
|
case "a":
|
||||||
addContact();
|
addContact(false);
|
||||||
contacts = ctx.addresses().getContacts();
|
contacts = ctx.addresses().getContacts();
|
||||||
break;
|
break;
|
||||||
case "b":
|
case "b":
|
||||||
@ -197,7 +198,7 @@ public class Application {
|
|||||||
} while (!"b".equals(command));
|
} while (!"b".equals(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContact() {
|
private void addContact(boolean isSubscription) {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("Please enter the Bitmessage address you want to add");
|
System.out.println("Please enter the Bitmessage address you want to add");
|
||||||
try {
|
try {
|
||||||
@ -207,12 +208,56 @@ public class Application {
|
|||||||
if (alias.length() > 0) {
|
if (alias.length() > 0) {
|
||||||
address.setAlias(alias);
|
address.setAlias(alias);
|
||||||
}
|
}
|
||||||
|
if (isSubscription) {
|
||||||
|
ctx.addSubscribtion(address);
|
||||||
|
}
|
||||||
ctx.addContact(address);
|
ctx.addContact(address);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void subscriptions() {
|
||||||
|
String command;
|
||||||
|
List<BitmessageAddress> subscriptions = ctx.addresses().getSubscriptions();
|
||||||
|
do {
|
||||||
|
System.out.println();
|
||||||
|
int i = 0;
|
||||||
|
for (BitmessageAddress contact : subscriptions) {
|
||||||
|
i++;
|
||||||
|
System.out.print(i + ") ");
|
||||||
|
if (contact.getAlias() != null) {
|
||||||
|
System.out.println(contact.getAlias() + " (" + contact.getAddress() + ")");
|
||||||
|
} else {
|
||||||
|
System.out.println(contact.getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
System.out.println("You have no subscriptions yet.");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("a) add subscription");
|
||||||
|
System.out.println("b) back");
|
||||||
|
|
||||||
|
command = nextCommand();
|
||||||
|
switch (command) {
|
||||||
|
case "a":
|
||||||
|
addContact(true);
|
||||||
|
subscriptions = ctx.addresses().getSubscriptions();
|
||||||
|
break;
|
||||||
|
case "b":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
int index = Integer.parseInt(command) - 1;
|
||||||
|
address(subscriptions.get(index));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.out.println("Unknown command. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!"b".equals(command));
|
||||||
|
}
|
||||||
|
|
||||||
private void address(BitmessageAddress address) {
|
private void address(BitmessageAddress address) {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
if (address.getAlias() != null)
|
if (address.getAlias() != null)
|
||||||
@ -244,12 +289,16 @@ public class Application {
|
|||||||
}
|
}
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("c) compose message");
|
System.out.println("c) compose message");
|
||||||
|
System.out.println("s) compose broadcast");
|
||||||
System.out.println("b) back");
|
System.out.println("b) back");
|
||||||
|
|
||||||
command = scanner.nextLine().trim();
|
command = scanner.nextLine().trim();
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "c":
|
case "c":
|
||||||
compose();
|
compose(false);
|
||||||
|
break;
|
||||||
|
case "s":
|
||||||
|
compose(true);
|
||||||
break;
|
break;
|
||||||
case "b":
|
case "b":
|
||||||
return;
|
return;
|
||||||
@ -272,7 +321,7 @@ public class Application {
|
|||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println(message.getText());
|
System.out.println(message.getText());
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("Labels: "+ message.getLabels());
|
System.out.println("Labels: " + message.getLabels());
|
||||||
System.out.println();
|
System.out.println();
|
||||||
String command;
|
String command;
|
||||||
do {
|
do {
|
||||||
@ -294,10 +343,10 @@ public class Application {
|
|||||||
} while (!"b".equalsIgnoreCase(command));
|
} while (!"b".equalsIgnoreCase(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compose() {
|
private void compose(boolean broadcast) {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
BitmessageAddress from = selectAddress(true);
|
BitmessageAddress from = selectAddress(true);
|
||||||
BitmessageAddress to = selectAddress(false);
|
BitmessageAddress to = (broadcast ? null : selectAddress(false));
|
||||||
|
|
||||||
compose(from, to, null);
|
compose(from, to, null);
|
||||||
}
|
}
|
||||||
@ -352,9 +401,12 @@ public class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void compose(BitmessageAddress from, BitmessageAddress to, String subject) {
|
private void compose(BitmessageAddress from, BitmessageAddress to, String subject) {
|
||||||
|
boolean broadcast = (to == null);
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("From: " + from);
|
System.out.println("From: " + from);
|
||||||
System.out.println("To: " + to);
|
if (!broadcast) {
|
||||||
|
System.out.println("To: " + to);
|
||||||
|
}
|
||||||
if (subject != null) {
|
if (subject != null) {
|
||||||
System.out.println("Subject: " + subject);
|
System.out.println("Subject: " + subject);
|
||||||
} else {
|
} else {
|
||||||
@ -368,7 +420,11 @@ public class Application {
|
|||||||
line = nextCommand();
|
line = nextCommand();
|
||||||
message.append(line).append('\n');
|
message.append(line).append('\n');
|
||||||
} while (line.length() > 0 || !yesNo("Send message?"));
|
} while (line.length() > 0 || !yesNo("Send message?"));
|
||||||
ctx.send(from, to, subject, message.toString());
|
if (broadcast) {
|
||||||
|
ctx.broadcast(from, subject, message.toString());
|
||||||
|
} else {
|
||||||
|
ctx.send(from, to, subject, message.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean yesNo(String question) {
|
private boolean yesNo(String question) {
|
||||||
|
@ -16,71 +16,12 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.demo;
|
package ch.dissem.bitmessage.demo;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.BitmessageContext;
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
|
||||||
import ch.dissem.bitmessage.entity.Plaintext;
|
|
||||||
import ch.dissem.bitmessage.networking.NetworkNode;
|
|
||||||
import ch.dissem.bitmessage.repository.JdbcAddressRepository;
|
|
||||||
import ch.dissem.bitmessage.repository.JdbcInventory;
|
|
||||||
import ch.dissem.bitmessage.repository.JdbcMessageRepository;
|
|
||||||
import ch.dissem.bitmessage.repository.JdbcNodeRegistry;
|
|
||||||
import ch.dissem.bitmessage.utils.Base58;
|
|
||||||
import ch.dissem.bitmessage.utils.Encode;
|
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by chris on 06.04.15.
|
|
||||||
*/
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
final BitmessageAddress address = new BitmessageAddress("BM-87hJ99tPAXxtetvnje7Z491YSvbEtBJVc5e");
|
// System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "TRACE");
|
||||||
|
// System.setProperty("org.slf4j.simpleLogger.logFile", "./trace.log");
|
||||||
new Application();
|
new Application();
|
||||||
//
|
|
||||||
//
|
|
||||||
// List<ObjectMessage> objects = new JdbcInventory().getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY);
|
|
||||||
// System.out.println("Address version: " + address.getVersion());
|
|
||||||
// System.out.println("Address stream: " + address.getStream());
|
|
||||||
// for (ObjectMessage o : objects) {
|
|
||||||
//// if (!o.isSignatureValid()) System.out.println("Invalid signature.");
|
|
||||||
//// System.out.println(o.getPayload().getSignature().length);
|
|
||||||
// V4Pubkey pubkey = (V4Pubkey) o.getPayload();
|
|
||||||
// if (Arrays.equals(address.getTag(), pubkey.getTag())) {
|
|
||||||
// System.out.println("Pubkey found!");
|
|
||||||
// try {
|
|
||||||
// System.out.println("IV: " + o.getInventoryVector());
|
|
||||||
// address.setPubkey(pubkey);
|
|
||||||
// } catch (Exception ignore) {
|
|
||||||
// System.out.println("But setPubkey failed? " + address.getRipe().length + "/" + pubkey.getRipe().length);
|
|
||||||
// System.out.println("Failed address: " + generateAddress(address.getStream(), address.getVersion(), pubkey.getRipe()));
|
|
||||||
// if (Arrays.equals(address.getRipe(), pubkey.getRipe())) {
|
|
||||||
// ignore.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String generateAddress(long stream, long version, byte[] ripe) {
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
||||||
Encode.varInt(version, os);
|
|
||||||
Encode.varInt(stream, os);
|
|
||||||
os.write(ripe);
|
|
||||||
|
|
||||||
byte[] checksum = Security.doubleSha512(os.toByteArray());
|
|
||||||
os.write(checksum, 0, 4);
|
|
||||||
return "BM-" + Base58.encode(os.toByteArray());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,11 @@ package ch.dissem.bitmessage;
|
|||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
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.Plaintext.Encoding;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.*;
|
import ch.dissem.bitmessage.entity.payload.*;
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
|
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
|
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||||
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.*;
|
import ch.dissem.bitmessage.ports.*;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
import ch.dissem.bitmessage.utils.UnixTime;
|
import ch.dissem.bitmessage.utils.UnixTime;
|
||||||
@ -35,6 +36,8 @@ import java.util.Collection;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
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.MSG;
|
||||||
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
|
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,6 +62,8 @@ public class BitmessageContext {
|
|||||||
|
|
||||||
private final InternalContext ctx;
|
private final InternalContext ctx;
|
||||||
|
|
||||||
|
private Listener listener;
|
||||||
|
|
||||||
private BitmessageContext(Builder builder) {
|
private BitmessageContext(Builder builder) {
|
||||||
ctx = new InternalContext(builder);
|
ctx = new InternalContext(builder);
|
||||||
}
|
}
|
||||||
@ -89,12 +94,34 @@ public class BitmessageContext {
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void broadcast(BitmessageAddress from, String subject, String message) {
|
||||||
|
// TODO: all this should happen in a separate thread
|
||||||
|
Plaintext msg = new Plaintext.Builder(BROADCAST)
|
||||||
|
.from(from)
|
||||||
|
.message(subject, message)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
LOG.info("Sending message.");
|
||||||
|
msg.setStatus(DOING_PROOF_OF_WORK);
|
||||||
|
ctx.getMessageRepository().save(msg);
|
||||||
|
ctx.send(
|
||||||
|
from,
|
||||||
|
from,
|
||||||
|
Factory.getBroadcast(from, msg),
|
||||||
|
+2 * DAY,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
msg.setStatus(SENT);
|
||||||
|
ctx.getMessageRepository().save(msg);
|
||||||
|
}
|
||||||
|
|
||||||
public void send(BitmessageAddress from, BitmessageAddress to, String subject, String message) {
|
public void send(BitmessageAddress from, BitmessageAddress to, String subject, 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.");
|
||||||
}
|
}
|
||||||
// TODO: all this should happen in a separate thread
|
// TODO: all this should happen in a separate thread
|
||||||
Plaintext msg = new Plaintext.Builder()
|
Plaintext msg = new Plaintext.Builder(MSG)
|
||||||
.from(from)
|
.from(from)
|
||||||
.to(to)
|
.to(to)
|
||||||
.message(subject, message)
|
.message(subject, message)
|
||||||
@ -154,6 +181,7 @@ public class BitmessageContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startup(Listener listener) {
|
public void startup(Listener listener) {
|
||||||
|
this.listener = listener;
|
||||||
ctx.getNetworkHandler().start(new DefaultMessageListener(ctx, listener));
|
ctx.getNetworkHandler().start(new DefaultMessageListener(ctx, listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +204,7 @@ public class BitmessageContext {
|
|||||||
if (address.getVersion() == 4) {
|
if (address.getVersion() == 4) {
|
||||||
V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
|
V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
|
||||||
if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) {
|
if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) {
|
||||||
v4Pubkey.decrypt(address.getPubkeyDecryptionKey());
|
v4Pubkey.decrypt(address.getPublicDecryptionKey());
|
||||||
if (object.isSignatureValid(v4Pubkey)) {
|
if (object.isSignatureValid(v4Pubkey)) {
|
||||||
address.setPubkey(v4Pubkey);
|
address.setPubkey(v4Pubkey);
|
||||||
ctx.getAddressRepo().save(address);
|
ctx.getAddressRepo().save(address);
|
||||||
@ -198,6 +226,25 @@ public class BitmessageContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addSubscribtion(BitmessageAddress address) {
|
||||||
|
address.setSubscribed(true);
|
||||||
|
ctx.getAddressRepo().save(address);
|
||||||
|
tryToFindBroadcastsForAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryToFindBroadcastsForAddress(BitmessageAddress address) {
|
||||||
|
for (ObjectMessage object : ctx.getInventory().getObjects(address.getStream(), Broadcast.getVersion(address), ObjectType.BROADCAST)) {
|
||||||
|
try {
|
||||||
|
Broadcast broadcast = (Broadcast) object.getPayload();
|
||||||
|
broadcast.decrypt(address);
|
||||||
|
listener.receive(broadcast.getPlaintext());
|
||||||
|
} catch (DecryptionFailedException ignore) {
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.debug(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void receive(Plaintext plaintext);
|
void receive(Plaintext plaintext);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
|
V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
|
||||||
address = ctx.getAddressRepo().findContact(v4Pubkey.getTag());
|
address = ctx.getAddressRepo().findContact(v4Pubkey.getTag());
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
v4Pubkey.decrypt(address.getPubkeyDecryptionKey());
|
v4Pubkey.decrypt(address.getPublicDecryptionKey());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
address = ctx.getAddressRepo().findContact(pubkey.getRipe());
|
address = ctx.getAddressRepo().findContact(pubkey.getRipe());
|
||||||
@ -91,8 +91,8 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
address.setPubkey(pubkey);
|
address.setPubkey(pubkey);
|
||||||
LOG.debug("Got pubkey for contact " + address);
|
LOG.debug("Got pubkey for contact " + address);
|
||||||
List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address);
|
List<Plaintext> messages = ctx.getMessageRepository().findMessages(Plaintext.Status.PUBKEY_REQUESTED, address);
|
||||||
|
LOG.debug("Sending " + messages.size() + " messages for contact " + address);
|
||||||
for (Plaintext msg : messages) {
|
for (Plaintext msg : messages) {
|
||||||
// TODO: send messages enqueued for this address
|
|
||||||
msg.setStatus(DOING_PROOF_OF_WORK);
|
msg.setStatus(DOING_PROOF_OF_WORK);
|
||||||
ctx.getMessageRepository().save(msg);
|
ctx.getMessageRepository().save(msg);
|
||||||
ctx.send(
|
ctx.send(
|
||||||
@ -118,14 +118,18 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
try {
|
try {
|
||||||
msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey());
|
msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey());
|
||||||
msg.getPlaintext().setTo(identity);
|
msg.getPlaintext().setTo(identity);
|
||||||
object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey());
|
if (!object.isSignatureValid(msg.getPlaintext().getFrom().getPubkey())) {
|
||||||
msg.getPlaintext().setStatus(RECEIVED);
|
LOG.warn("Msg with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
|
||||||
msg.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD));
|
} else {
|
||||||
ctx.getMessageRepository().save(msg.getPlaintext());
|
msg.getPlaintext().setStatus(RECEIVED);
|
||||||
listener.receive(msg.getPlaintext());
|
msg.getPlaintext().addLabels(ctx.getMessageRepository().getLabels(Label.Type.INBOX, Label.Type.UNREAD));
|
||||||
|
msg.getPlaintext().setInventoryVector(object.getInventoryVector());
|
||||||
|
ctx.getMessageRepository().save(msg.getPlaintext());
|
||||||
|
listener.receive(msg.getPlaintext());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
} catch (DecryptionFailedException ignore) {
|
} catch (DecryptionFailedException ignore) {
|
||||||
LOG.debug(ignore.getMessage(), ignore);
|
LOG.trace(ignore.getMessage(), ignore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,9 +139,13 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
// V5Broadcast v5 = broadcast instanceof V5Broadcast ? (V5Broadcast) broadcast : null;
|
// V5Broadcast v5 = broadcast instanceof V5Broadcast ? (V5Broadcast) broadcast : null;
|
||||||
for (BitmessageAddress subscription : ctx.getAddressRepo().getSubscriptions()) {
|
for (BitmessageAddress subscription : ctx.getAddressRepo().getSubscriptions()) {
|
||||||
try {
|
try {
|
||||||
broadcast.decrypt(subscription.getPubkeyDecryptionKey());
|
broadcast.decrypt(subscription.getPublicDecryptionKey());
|
||||||
object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey());
|
if (!object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey())) {
|
||||||
listener.receive(broadcast.getPlaintext());
|
LOG.warn("Broadcast with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
|
||||||
|
} else {
|
||||||
|
broadcast.getPlaintext().setInventoryVector(object.getInventoryVector());
|
||||||
|
listener.receive(broadcast.getPlaintext());
|
||||||
|
}
|
||||||
} catch (DecryptionFailedException ignore) {
|
} catch (DecryptionFailedException ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,8 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage;
|
package ch.dissem.bitmessage;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.*;
|
||||||
import ch.dissem.bitmessage.entity.Encrypted;
|
import ch.dissem.bitmessage.entity.payload.Broadcast;
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.GetPubkey;
|
import ch.dissem.bitmessage.entity.payload.GetPubkey;
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
||||||
import ch.dissem.bitmessage.ports.*;
|
import ch.dissem.bitmessage.ports.*;
|
||||||
@ -141,6 +140,7 @@ public class InternalContext {
|
|||||||
|
|
||||||
public void send(BitmessageAddress from, BitmessageAddress to, ObjectPayload payload, long timeToLive, long nonceTrialsPerByte, long extraBytes) {
|
public void send(BitmessageAddress from, BitmessageAddress to, ObjectPayload payload, long timeToLive, long nonceTrialsPerByte, long extraBytes) {
|
||||||
try {
|
try {
|
||||||
|
if (to == null) to = from;
|
||||||
long expires = UnixTime.now(+timeToLive);
|
long expires = UnixTime.now(+timeToLive);
|
||||||
LOG.info("Expires at " + expires);
|
LOG.info("Expires at " + expires);
|
||||||
ObjectMessage object = new ObjectMessage.Builder()
|
ObjectMessage object = new ObjectMessage.Builder()
|
||||||
@ -151,10 +151,17 @@ public class InternalContext {
|
|||||||
if (object.isSigned()) {
|
if (object.isSigned()) {
|
||||||
object.sign(from.getPrivateKey());
|
object.sign(from.getPrivateKey());
|
||||||
}
|
}
|
||||||
if (payload instanceof Encrypted) {
|
if (payload instanceof Broadcast) {
|
||||||
|
((Broadcast) payload).encrypt();
|
||||||
|
} else if (payload instanceof Encrypted) {
|
||||||
object.encrypt(to.getPubkey());
|
object.encrypt(to.getPubkey());
|
||||||
}
|
}
|
||||||
Security.doProofOfWork(object, proofOfWorkEngine, nonceTrialsPerByte, extraBytes);
|
Security.doProofOfWork(object, proofOfWorkEngine, nonceTrialsPerByte, extraBytes);
|
||||||
|
if (payload instanceof PlaintextHolder) {
|
||||||
|
Plaintext plaintext = ((PlaintextHolder) payload).getPlaintext();
|
||||||
|
plaintext.setInventoryVector(object.getInventoryVector());
|
||||||
|
messageRepository.save(plaintext);
|
||||||
|
}
|
||||||
inventory.storeObject(object);
|
inventory.storeObject(object);
|
||||||
networkHandler.offer(object.getInventoryVector());
|
networkHandler.offer(object.getInventoryVector());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -172,13 +179,13 @@ public class InternalContext {
|
|||||||
.payload(identity.getPubkey())
|
.payload(identity.getPubkey())
|
||||||
.build();
|
.build();
|
||||||
response.sign(identity.getPrivateKey());
|
response.sign(identity.getPrivateKey());
|
||||||
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
|
response.encrypt(Security.createPublicKey(identity.getPublicDecryptionKey()).getEncoded(false));
|
||||||
Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes);
|
Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes);
|
||||||
if (response.isSigned()) {
|
if (response.isSigned()) {
|
||||||
response.sign(identity.getPrivateKey());
|
response.sign(identity.getPrivateKey());
|
||||||
}
|
}
|
||||||
if (response instanceof Encrypted) {
|
if (response instanceof Encrypted) {
|
||||||
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
|
response.encrypt(Security.createPublicKey(identity.getPublicDecryptionKey()).getEncoded(false));
|
||||||
}
|
}
|
||||||
inventory.storeObject(response);
|
inventory.storeObject(response);
|
||||||
networkHandler.offer(response.getInventoryVector());
|
networkHandler.offer(response.getInventoryVector());
|
||||||
|
@ -42,7 +42,7 @@ public class BitmessageAddress {
|
|||||||
/**
|
/**
|
||||||
* Used for V4 address encryption. It's easier to just create it regardless of address version.
|
* Used for V4 address encryption. It's easier to just create it regardless of address version.
|
||||||
*/
|
*/
|
||||||
private final byte[] pubkeyDecryptionKey;
|
private final byte[] publicDecryptionKey;
|
||||||
|
|
||||||
private String address;
|
private String address;
|
||||||
|
|
||||||
@ -61,14 +61,20 @@ public class BitmessageAddress {
|
|||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
Encode.varInt(version, os);
|
Encode.varInt(version, os);
|
||||||
Encode.varInt(stream, os);
|
Encode.varInt(stream, os);
|
||||||
// for the tag, the checksum has to be created with 0x00 padding
|
if (version < 4) {
|
||||||
byte[] checksum = Security.doubleSha512(os.toByteArray(), ripe);
|
byte[] checksum = Security.sha512(os.toByteArray(), ripe);
|
||||||
this.tag = Arrays.copyOfRange(checksum, 32, 64);
|
this.tag = null;
|
||||||
this.pubkeyDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
|
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
|
||||||
|
} else {
|
||||||
|
// for tag and decryption key, the checksum has to be created with 0x00 padding
|
||||||
|
byte[] checksum = Security.doubleSha512(os.toByteArray(), ripe);
|
||||||
|
this.tag = Arrays.copyOfRange(checksum, 32, 64);
|
||||||
|
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
|
||||||
|
}
|
||||||
// but for the address and its checksum they need to be stripped
|
// but for the address and its checksum they need to be stripped
|
||||||
int offset = Bytes.numberOfLeadingZeros(ripe);
|
int offset = Bytes.numberOfLeadingZeros(ripe);
|
||||||
os.write(ripe, offset, ripe.length - offset);
|
os.write(ripe, offset, ripe.length - offset);
|
||||||
checksum = Security.doubleSha512(os.toByteArray());
|
byte[] checksum = Security.doubleSha512(os.toByteArray());
|
||||||
os.write(checksum, 0, 4);
|
os.write(checksum, 0, 4);
|
||||||
this.address = "BM-" + Base58.encode(os.toByteArray());
|
this.address = "BM-" + Base58.encode(os.toByteArray());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -103,9 +109,15 @@ public class BitmessageAddress {
|
|||||||
if (expectedChecksum[i] != checksum[i])
|
if (expectedChecksum[i] != checksum[i])
|
||||||
throw new IllegalArgumentException("Checksum of address failed");
|
throw new IllegalArgumentException("Checksum of address failed");
|
||||||
}
|
}
|
||||||
checksum = Security.doubleSha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
|
if (version < 4) {
|
||||||
this.tag = Arrays.copyOfRange(checksum, 32, 64);
|
checksum = Security.sha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
|
||||||
this.pubkeyDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
|
this.tag = null;
|
||||||
|
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
|
||||||
|
} else {
|
||||||
|
checksum = Security.doubleSha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
|
||||||
|
this.tag = Arrays.copyOfRange(checksum, 32, 64);
|
||||||
|
this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -145,8 +157,11 @@ public class BitmessageAddress {
|
|||||||
this.pubkey = pubkey;
|
this.pubkey = pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getPubkeyDecryptionKey() {
|
/**
|
||||||
return pubkeyDecryptionKey;
|
* Returns the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts.
|
||||||
|
*/
|
||||||
|
public byte[] getPublicDecryptionKey() {
|
||||||
|
return publicDecryptionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrivateKey getPrivateKey() {
|
public PrivateKey getPrivateKey() {
|
||||||
@ -165,10 +180,6 @@ public class BitmessageAddress {
|
|||||||
this.alias = alias;
|
this.alias = alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSubscribed(boolean subscribed) {
|
|
||||||
this.subscribed = subscribed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return alias != null ? alias : address;
|
return alias != null ? alias : address;
|
||||||
@ -196,4 +207,12 @@ public class BitmessageAddress {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Arrays.hashCode(ripe);
|
return Arrays.hashCode(ripe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSubscribed() {
|
||||||
|
return subscribed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscribed(boolean subscribed) {
|
||||||
|
this.subscribed = subscribed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity;
|
package ch.dissem.bitmessage.entity;
|
||||||
|
|
||||||
|
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.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.utils.Decode;
|
import ch.dissem.bitmessage.utils.Decode;
|
||||||
@ -28,11 +29,13 @@ import java.util.*;
|
|||||||
* The unencrypted message to be sent by 'msg' or 'broadcast'.
|
* The unencrypted message to be sent by 'msg' or 'broadcast'.
|
||||||
*/
|
*/
|
||||||
public class Plaintext implements Streamable {
|
public class Plaintext implements Streamable {
|
||||||
|
private final Type type;
|
||||||
private final BitmessageAddress from;
|
private final BitmessageAddress from;
|
||||||
private final long encoding;
|
private final long encoding;
|
||||||
private final byte[] message;
|
private final byte[] message;
|
||||||
private final byte[] ack;
|
private final byte[] ack;
|
||||||
private Object id;
|
private Object id;
|
||||||
|
private InventoryVector inventoryVector;
|
||||||
private BitmessageAddress to;
|
private BitmessageAddress to;
|
||||||
private byte[] signature;
|
private byte[] signature;
|
||||||
private Status status;
|
private Status status;
|
||||||
@ -43,6 +46,8 @@ public class Plaintext implements Streamable {
|
|||||||
|
|
||||||
private Plaintext(Builder builder) {
|
private Plaintext(Builder builder) {
|
||||||
id = builder.id;
|
id = builder.id;
|
||||||
|
inventoryVector = builder.inventoryVector;
|
||||||
|
type = builder.type;
|
||||||
from = builder.from;
|
from = builder.from;
|
||||||
to = builder.to;
|
to = builder.to;
|
||||||
encoding = builder.encoding;
|
encoding = builder.encoding;
|
||||||
@ -55,14 +60,14 @@ public class Plaintext implements Streamable {
|
|||||||
labels = builder.labels;
|
labels = builder.labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Plaintext read(InputStream in) throws IOException {
|
public static Plaintext read(Type type, InputStream in) throws IOException {
|
||||||
return readWithoutSignature(in)
|
return readWithoutSignature(type, in)
|
||||||
.signature(Decode.varBytes(in))
|
.signature(Decode.varBytes(in))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Plaintext.Builder readWithoutSignature(InputStream in) throws IOException {
|
public static Plaintext.Builder readWithoutSignature(Type type, InputStream in) throws IOException {
|
||||||
return new Builder()
|
return new Builder(type)
|
||||||
.addressVersion(Decode.varInt(in))
|
.addressVersion(Decode.varInt(in))
|
||||||
.stream(Decode.varInt(in))
|
.stream(Decode.varInt(in))
|
||||||
.behaviorBitfield(Decode.int32(in))
|
.behaviorBitfield(Decode.int32(in))
|
||||||
@ -70,10 +75,22 @@ public class Plaintext implements Streamable {
|
|||||||
.publicEncryptionKey(Decode.bytes(in, 64))
|
.publicEncryptionKey(Decode.bytes(in, 64))
|
||||||
.nonceTrialsPerByte(Decode.varInt(in))
|
.nonceTrialsPerByte(Decode.varInt(in))
|
||||||
.extraBytes(Decode.varInt(in))
|
.extraBytes(Decode.varInt(in))
|
||||||
.destinationRipe(Decode.bytes(in, 20))
|
.destinationRipe(type == Type.MSG ? Decode.bytes(in, 20) : null)
|
||||||
.encoding(Decode.varInt(in))
|
.encoding(Decode.varInt(in))
|
||||||
.message(Decode.varBytes(in))
|
.message(Decode.varBytes(in))
|
||||||
.ack(Decode.varBytes(in));
|
.ack(type == Type.MSG ? Decode.varBytes(in) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryVector getInventoryVector() {
|
||||||
|
return inventoryVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventoryVector(InventoryVector inventoryVector) {
|
||||||
|
this.inventoryVector = inventoryVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getMessage() {
|
public byte[] getMessage() {
|
||||||
@ -121,12 +138,16 @@ public class Plaintext implements Streamable {
|
|||||||
out.write(from.getPubkey().getEncryptionKey(), 1, 64);
|
out.write(from.getPubkey().getEncryptionKey(), 1, 64);
|
||||||
Encode.varInt(from.getPubkey().getNonceTrialsPerByte(), out);
|
Encode.varInt(from.getPubkey().getNonceTrialsPerByte(), out);
|
||||||
Encode.varInt(from.getPubkey().getExtraBytes(), out);
|
Encode.varInt(from.getPubkey().getExtraBytes(), out);
|
||||||
out.write(to.getRipe());
|
if (type == Type.MSG) {
|
||||||
|
out.write(to.getRipe());
|
||||||
|
}
|
||||||
Encode.varInt(encoding, out);
|
Encode.varInt(encoding, out);
|
||||||
Encode.varInt(message.length, out);
|
Encode.varInt(message.length, out);
|
||||||
out.write(message);
|
out.write(message);
|
||||||
Encode.varInt(ack.length, out);
|
if (type == Type.MSG) {
|
||||||
out.write(ack);
|
Encode.varInt(ack.length, out);
|
||||||
|
out.write(ack);
|
||||||
|
}
|
||||||
if (includeSignature) {
|
if (includeSignature) {
|
||||||
if (signature == null) {
|
if (signature == null) {
|
||||||
Encode.varInt(0, out);
|
Encode.varInt(0, out);
|
||||||
@ -249,8 +270,14 @@ public class Plaintext implements Streamable {
|
|||||||
RECEIVED
|
RECEIVED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
MSG, BROADCAST
|
||||||
|
}
|
||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
private Object id;
|
private Object id;
|
||||||
|
private InventoryVector inventoryVector;
|
||||||
|
private Type type;
|
||||||
private BitmessageAddress from;
|
private BitmessageAddress from;
|
||||||
private BitmessageAddress to;
|
private BitmessageAddress to;
|
||||||
private long addressVersion;
|
private long addressVersion;
|
||||||
@ -270,7 +297,8 @@ public class Plaintext implements Streamable {
|
|||||||
private Status status;
|
private Status status;
|
||||||
private Set<Label> labels = new HashSet<>();
|
private Set<Label> labels = new HashSet<>();
|
||||||
|
|
||||||
public Builder() {
|
public Builder(Type type) {
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder id(Object id) {
|
public Builder id(Object id) {
|
||||||
@ -278,12 +306,19 @@ public class Plaintext implements Streamable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder IV(InventoryVector iv) {
|
||||||
|
this.inventoryVector = iv;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder from(BitmessageAddress address) {
|
public Builder from(BitmessageAddress address) {
|
||||||
from = address;
|
from = address;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder to(BitmessageAddress address) {
|
public Builder to(BitmessageAddress address) {
|
||||||
|
if (type != Type.MSG && to != null)
|
||||||
|
throw new IllegalArgumentException("recipient address only allowed for msg");
|
||||||
to = address;
|
to = address;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -324,6 +359,7 @@ public class Plaintext implements Streamable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Builder destinationRipe(byte[] ripe) {
|
private Builder destinationRipe(byte[] ripe) {
|
||||||
|
if (type != Type.MSG && ripe != null) throw new IllegalArgumentException("ripe only allowed for msg");
|
||||||
this.destinationRipe = ripe;
|
this.destinationRipe = ripe;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -354,6 +390,7 @@ public class Plaintext implements Streamable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Builder ack(byte[] ack) {
|
public Builder ack(byte[] ack) {
|
||||||
|
if (type != Type.MSG && ack != null) throw new IllegalArgumentException("ack only allowed for msg");
|
||||||
this.ack = ack;
|
this.ack = ack;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -395,7 +432,7 @@ public class Plaintext implements Streamable {
|
|||||||
behaviorBitfield
|
behaviorBitfield
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (to == null) {
|
if (to == null && type != Type.BROADCAST) {
|
||||||
to = new BitmessageAddress(0, 0, destinationRipe);
|
to = new BitmessageAddress(0, 0, destinationRipe);
|
||||||
}
|
}
|
||||||
return new Plaintext(this);
|
return new Plaintext(this);
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.entity;
|
||||||
|
|
||||||
|
public interface PlaintextHolder {
|
||||||
|
Plaintext getPlaintext();
|
||||||
|
}
|
@ -16,17 +16,22 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload;
|
package ch.dissem.bitmessage.entity.payload;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.Encrypted;
|
import ch.dissem.bitmessage.entity.Encrypted;
|
||||||
import ch.dissem.bitmessage.entity.Plaintext;
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
|
import ch.dissem.bitmessage.entity.PlaintextHolder;
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||||
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Users who are subscribed to the sending address will see the message appear in their inbox.
|
* Users who are subscribed to the sending address will see the message appear in their inbox.
|
||||||
* Broadcasts are version 4 or 5.
|
* Broadcasts are version 4 or 5.
|
||||||
*/
|
*/
|
||||||
public abstract class Broadcast extends ObjectPayload implements Encrypted {
|
public abstract class Broadcast extends ObjectPayload implements Encrypted, PlaintextHolder {
|
||||||
protected final long stream;
|
protected final long stream;
|
||||||
protected CryptoBox encrypted;
|
protected CryptoBox encrypted;
|
||||||
protected Plaintext plaintext;
|
protected Plaintext plaintext;
|
||||||
@ -38,11 +43,16 @@ public abstract class Broadcast extends ObjectPayload implements Encrypted {
|
|||||||
this.plaintext = plaintext;
|
this.plaintext = plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getVersion(BitmessageAddress address) {
|
||||||
|
return address.getVersion() < 4 ? 4 : 5;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getStream() {
|
public long getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Plaintext getPlaintext() {
|
public Plaintext getPlaintext() {
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
@ -52,9 +62,17 @@ public abstract class Broadcast extends ObjectPayload implements Encrypted {
|
|||||||
this.encrypted = new CryptoBox(plaintext, publicKey);
|
this.encrypted = new CryptoBox(plaintext, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void encrypt() throws IOException {
|
||||||
|
encrypt(Security.createPublicKey(plaintext.getFrom().getPublicDecryptionKey()).getEncoded(false));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException {
|
public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException {
|
||||||
plaintext = Plaintext.read(encrypted.decrypt(privateKey));
|
plaintext = Plaintext.read(BROADCAST, encrypted.decrypt(privateKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decrypt(BitmessageAddress address) throws IOException, DecryptionFailedException {
|
||||||
|
decrypt(address.getPublicDecryptionKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,16 +18,19 @@ package ch.dissem.bitmessage.entity.payload;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.Encrypted;
|
import ch.dissem.bitmessage.entity.Encrypted;
|
||||||
import ch.dissem.bitmessage.entity.Plaintext;
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
|
import ch.dissem.bitmessage.entity.PlaintextHolder;
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for person-to-person messages.
|
* Used for person-to-person messages.
|
||||||
*/
|
*/
|
||||||
public class Msg extends ObjectPayload implements Encrypted {
|
public class Msg extends ObjectPayload implements Encrypted, PlaintextHolder {
|
||||||
private long stream;
|
private long stream;
|
||||||
private CryptoBox encrypted;
|
private CryptoBox encrypted;
|
||||||
private Plaintext plaintext;
|
private Plaintext plaintext;
|
||||||
@ -48,6 +51,7 @@ public class Msg extends ObjectPayload implements Encrypted {
|
|||||||
return new Msg(stream, CryptoBox.read(in, length));
|
return new Msg(stream, CryptoBox.read(in, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Plaintext getPlaintext() {
|
public Plaintext getPlaintext() {
|
||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
@ -89,7 +93,7 @@ public class Msg extends ObjectPayload implements Encrypted {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException {
|
public void decrypt(byte[] privateKey) throws IOException, DecryptionFailedException {
|
||||||
plaintext = Plaintext.read(encrypted.decrypt(privateKey));
|
plaintext = Plaintext.read(MSG, encrypted.decrypt(privateKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload;
|
package ch.dissem.bitmessage.entity.payload;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -25,12 +28,18 @@ import java.io.OutputStream;
|
|||||||
* Broadcasts are version 4 or 5.
|
* Broadcasts are version 4 or 5.
|
||||||
*/
|
*/
|
||||||
public class V4Broadcast extends Broadcast {
|
public class V4Broadcast extends Broadcast {
|
||||||
protected V4Broadcast(long version, long stream, CryptoBox encrypted) {
|
protected V4Broadcast(long version, long stream, CryptoBox encrypted, Plaintext plaintext) {
|
||||||
super(version, stream, encrypted, null);
|
super(version, stream, encrypted, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V4Broadcast(BitmessageAddress senderAddress, Plaintext plaintext) {
|
||||||
|
super(4, senderAddress.getStream(), null, plaintext);
|
||||||
|
if (senderAddress.getVersion() >= 4)
|
||||||
|
throw new IllegalArgumentException("Address version 3 or older expected, but was " + senderAddress.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static V4Broadcast read(InputStream in, long stream, int length) throws IOException {
|
public static V4Broadcast read(InputStream in, long stream, int length) throws IOException {
|
||||||
return new V4Broadcast(4, stream, CryptoBox.read(in, length));
|
return new V4Broadcast(4, stream, CryptoBox.read(in, length), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload;
|
package ch.dissem.bitmessage.entity.payload;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
import ch.dissem.bitmessage.utils.Decode;
|
import ch.dissem.bitmessage.utils.Decode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -29,10 +31,17 @@ public class V5Broadcast extends V4Broadcast {
|
|||||||
private byte[] tag;
|
private byte[] tag;
|
||||||
|
|
||||||
private V5Broadcast(long stream, byte[] tag, CryptoBox encrypted) {
|
private V5Broadcast(long stream, byte[] tag, CryptoBox encrypted) {
|
||||||
super(5, stream, encrypted);
|
super(5, stream, encrypted, null);
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public V5Broadcast(BitmessageAddress senderAddress, Plaintext plaintext) {
|
||||||
|
super(5, senderAddress.getStream(), null, plaintext);
|
||||||
|
if (senderAddress.getVersion() < 4)
|
||||||
|
throw new IllegalArgumentException("Address version 4 (or newer) expected, but was " + senderAddress.getVersion());
|
||||||
|
this.tag = senderAddress.getTag();
|
||||||
|
}
|
||||||
|
|
||||||
public static V5Broadcast read(InputStream is, long stream, int length) throws IOException {
|
public static V5Broadcast read(InputStream is, long stream, int length) throws IOException {
|
||||||
return new V5Broadcast(stream, Decode.bytes(is, 32), CryptoBox.read(is, length - 32));
|
return new V5Broadcast(stream, Decode.bytes(is, 32), CryptoBox.read(is, length - 32));
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package ch.dissem.bitmessage.factory;
|
|||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.NetworkMessage;
|
import ch.dissem.bitmessage.entity.NetworkMessage;
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
import ch.dissem.bitmessage.entity.payload.*;
|
import ch.dissem.bitmessage.entity.payload.*;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -164,4 +165,12 @@ public class Factory {
|
|||||||
return GenericPayload.read(version, stream, streamNumber, length);
|
return GenericPayload.read(version, stream, streamNumber, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ObjectPayload getBroadcast(BitmessageAddress sendingAddress, Plaintext plaintext) {
|
||||||
|
if (sendingAddress.getVersion() < 4) {
|
||||||
|
return new V4Broadcast(sendingAddress, plaintext);
|
||||||
|
} else {
|
||||||
|
return new V5Broadcast(sendingAddress, plaintext);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.utils;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DebugUtils {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(DebugUtils.class);
|
||||||
|
|
||||||
|
public static void saveToFile(ObjectMessage objectMessage) {
|
||||||
|
try {
|
||||||
|
File f = new File(System.getProperty("user.home") + "/jabit.error/" + objectMessage.getInventoryVector() + ".inv");
|
||||||
|
f.createNewFile();
|
||||||
|
objectMessage.write(new FileOutputStream(f));
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.debug(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V4Broadcast;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V5Broadcast;
|
||||||
|
import ch.dissem.bitmessage.exception.DecryptionFailedException;
|
||||||
|
import ch.dissem.bitmessage.utils.TestUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class DecryptionTest {
|
||||||
|
@Test
|
||||||
|
public void ensureV4BroadcastIsDecryptedCorrectly() throws IOException, DecryptionFailedException {
|
||||||
|
ObjectMessage objectMessage = TestUtils.loadObjectMessage(5, "V4Broadcast.payload");
|
||||||
|
V4Broadcast broadcast = (V4Broadcast) objectMessage.getPayload();
|
||||||
|
broadcast.decrypt(new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ"));
|
||||||
|
assertEquals("Test-Broadcast", broadcast.getPlaintext().getSubject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureV5BroadcastIsDecryptedCorrectly() throws IOException, DecryptionFailedException {
|
||||||
|
ObjectMessage objectMessage = TestUtils.loadObjectMessage(5, "V5Broadcast.payload");
|
||||||
|
V5Broadcast broadcast = (V5Broadcast) objectMessage.getPayload();
|
||||||
|
broadcast.decrypt(new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h"));
|
||||||
|
assertEquals("Test-Broadcast", broadcast.getPlaintext().getSubject());
|
||||||
|
}
|
||||||
|
}
|
@ -84,7 +84,7 @@ public class BitmessageAddressTest {
|
|||||||
public void testV4PubkeyImport() throws IOException, DecryptionFailedException {
|
public void testV4PubkeyImport() throws IOException, DecryptionFailedException {
|
||||||
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
|
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
|
||||||
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
|
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
|
||||||
object.decrypt(address.getPubkeyDecryptionKey());
|
object.decrypt(address.getPublicDecryptionKey());
|
||||||
V4Pubkey pubkey = (V4Pubkey) object.getPayload();
|
V4Pubkey pubkey = (V4Pubkey) object.getPayload();
|
||||||
assertTrue(object.isSignatureValid(pubkey));
|
assertTrue(object.isSignatureValid(pubkey));
|
||||||
address.setPubkey(pubkey);
|
address.setPubkey(pubkey);
|
||||||
|
@ -27,6 +27,7 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@ -78,7 +79,7 @@ public class SerializationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException {
|
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException {
|
||||||
Plaintext p1 = new Plaintext.Builder()
|
Plaintext p1 = new Plaintext.Builder(MSG)
|
||||||
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
|
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
|
||||||
.to(TestUtils.loadContact())
|
.to(TestUtils.loadContact())
|
||||||
.message("Subject", "Message")
|
.message("Subject", "Message")
|
||||||
@ -88,7 +89,7 @@ public class SerializationTest {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
p1.write(out);
|
p1.write(out);
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
Plaintext p2 = Plaintext.read(in);
|
Plaintext p2 = Plaintext.read(MSG, in);
|
||||||
assertEquals(p1, p2);
|
assertEquals(p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class TestUtils {
|
|||||||
public static BitmessageAddress loadContact() throws IOException, DecryptionFailedException {
|
public static BitmessageAddress loadContact() throws IOException, DecryptionFailedException {
|
||||||
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
|
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
|
||||||
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
|
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
|
||||||
object.decrypt(address.getPubkeyDecryptionKey());
|
object.decrypt(address.getPublicDecryptionKey());
|
||||||
address.setPubkey((V4Pubkey) object.getPayload());
|
address.setPubkey((V4Pubkey) object.getPayload());
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
|
||||||
|
@ -24,6 +24,7 @@ import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
|||||||
import ch.dissem.bitmessage.exception.InsufficientProofOfWorkException;
|
import ch.dissem.bitmessage.exception.InsufficientProofOfWorkException;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler.MessageListener;
|
import ch.dissem.bitmessage.ports.NetworkHandler.MessageListener;
|
||||||
|
import ch.dissem.bitmessage.utils.DebugUtils;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -160,15 +161,10 @@ public class Connection implements Runnable {
|
|||||||
listener.receive(objectMessage);
|
listener.receive(objectMessage);
|
||||||
ctx.getInventory().storeObject(objectMessage);
|
ctx.getInventory().storeObject(objectMessage);
|
||||||
} catch (InsufficientProofOfWorkException e) {
|
} catch (InsufficientProofOfWorkException e) {
|
||||||
try {
|
// DebugUtils.saveToFile(objectMessage);
|
||||||
File f = new File(System.getProperty("user.home") + "/jabit.error/" + objectMessage.getInventoryVector() + ".inv");
|
|
||||||
f.createNewFile();
|
|
||||||
objectMessage.write(new FileOutputStream(f));
|
|
||||||
} catch (IOException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e);
|
LOG.error("Stream " + objectMessage.getStream() + ", object type " + objectMessage.getType() + ": " + e.getMessage(), e);
|
||||||
|
DebugUtils.saveToFile(objectMessage);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ADDR:
|
case ADDR:
|
||||||
|
@ -140,24 +140,27 @@ 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(
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
"UPDATE Address SET alias=?, public_key=?, private_key=? WHERE address=?");
|
"UPDATE Address SET alias=?, public_key=?, private_key=?, subscribed=? WHERE address=?");
|
||||||
ps.setString(1, address.getAlias());
|
ps.setString(1, address.getAlias());
|
||||||
writePubkey(ps, 2, address.getPubkey());
|
writePubkey(ps, 2, address.getPubkey());
|
||||||
writeBlob(ps, 3, address.getPrivateKey());
|
writeBlob(ps, 3, address.getPrivateKey());
|
||||||
ps.setString(4, address.getAddress());
|
ps.setBoolean(4, address.isSubscribed());
|
||||||
ps.executeUpdate();
|
ps.setString(5, address.getAddress());
|
||||||
}}
|
ps.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void insert(BitmessageAddress address) throws IOException, SQLException {
|
private void insert(BitmessageAddress address) throws IOException, SQLException {
|
||||||
try (Connection connection = config.getConnection()) {
|
try (Connection connection = config.getConnection()) {
|
||||||
PreparedStatement ps = connection.prepareStatement(
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
"INSERT INTO Address (address, alias, public_key, private_key) VALUES (?, ?, ?, ?)");
|
"INSERT INTO Address (address, alias, public_key, private_key, subscribed) VALUES (?, ?, ?, ?, ?)");
|
||||||
ps.setString(1, address.getAddress());
|
ps.setString(1, address.getAddress());
|
||||||
ps.setString(2, address.getAlias());
|
ps.setString(2, address.getAlias());
|
||||||
writePubkey(ps, 3, address.getPubkey());
|
writePubkey(ps, 3, address.getPubkey());
|
||||||
writeBlob(ps, 4, address.getPrivateKey());
|
writeBlob(ps, 4, address.getPrivateKey());
|
||||||
|
ps.setBoolean(5, address.isSubscribed());
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package ch.dissem.bitmessage.repository;
|
|||||||
import ch.dissem.bitmessage.InternalContext;
|
import ch.dissem.bitmessage.InternalContext;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.Plaintext;
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
|
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.ports.MessageRepository;
|
import ch.dissem.bitmessage.ports.MessageRepository;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -102,12 +103,15 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
List<Plaintext> result = new LinkedList<>();
|
List<Plaintext> result = new LinkedList<>();
|
||||||
try (Connection connection = config.getConnection()) {
|
try (Connection connection = config.getConnection()) {
|
||||||
Statement stmt = connection.createStatement();
|
Statement stmt = connection.createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT id, sender, recipient, data, sent, received, status FROM Message WHERE " + where);
|
ResultSet rs = stmt.executeQuery("SELECT id, iv, type, sender, recipient, data, sent, received, status FROM Message WHERE " + where);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
|
byte[] iv = rs.getBytes("iv");
|
||||||
Blob data = rs.getBlob("data");
|
Blob data = rs.getBlob("data");
|
||||||
Plaintext.Builder builder = Plaintext.readWithoutSignature(data.getBinaryStream());
|
Plaintext.Type type = Plaintext.Type.valueOf(rs.getString("type"));
|
||||||
|
Plaintext.Builder builder = Plaintext.readWithoutSignature(type, data.getBinaryStream());
|
||||||
long id = rs.getLong("id");
|
long id = rs.getLong("id");
|
||||||
builder.id(id);
|
builder.id(id);
|
||||||
|
builder.IV(new InventoryVector(iv));
|
||||||
builder.from(ctx.getAddressRepo().getAddress(rs.getString("sender")));
|
builder.from(ctx.getAddressRepo().getAddress(rs.getString("sender")));
|
||||||
builder.to(ctx.getAddressRepo().getAddress(rs.getString("recipient")));
|
builder.to(ctx.getAddressRepo().getAddress(rs.getString("recipient")));
|
||||||
builder.sent(rs.getLong("sent"));
|
builder.sent(rs.getLong("sent"));
|
||||||
@ -155,14 +159,14 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
// save message
|
// save message
|
||||||
if (message.getId() == null) {
|
if (message.getId() == null) {
|
||||||
insert(connection, message);
|
insert(connection, message);
|
||||||
|
|
||||||
// remove existing labels
|
|
||||||
Statement stmt = connection.createStatement();
|
|
||||||
stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId());
|
|
||||||
} else {
|
} else {
|
||||||
update(connection, message);
|
update(connection, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove existing labels
|
||||||
|
Statement stmt = connection.createStatement();
|
||||||
|
stmt.executeUpdate("DELETE FROM Message_Label WHERE message_id=" + message.getId());
|
||||||
|
|
||||||
// save labels
|
// save labels
|
||||||
PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + message.getId() + ", ?)");
|
PreparedStatement ps = connection.prepareStatement("INSERT INTO Message_Label VALUES (" + message.getId() + ", ?)");
|
||||||
for (Label label : message.getLabels()) {
|
for (Label label : message.getLabels()) {
|
||||||
@ -186,16 +190,15 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
|
|
||||||
private void insert(Connection connection, Plaintext message) throws SQLException, IOException {
|
private void insert(Connection connection, Plaintext message) throws SQLException, IOException {
|
||||||
PreparedStatement ps = connection.prepareStatement(
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
"INSERT INTO Message (sender, recipient, data, sent, received, status) VALUES (?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
|
"INSERT INTO Message (iv, type, sender, recipient, data, sent, received, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setString(1, message.getFrom().getAddress());
|
ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null);
|
||||||
ps.setString(2, message.getTo().getAddress());
|
ps.setString(2, message.getType().name());
|
||||||
writeBlob(ps, 3, message);
|
ps.setString(3, message.getFrom().getAddress());
|
||||||
ps.setLong(4, message.getSent());
|
ps.setString(4, message.getTo() != null ? message.getTo().getAddress() : null);
|
||||||
ps.setLong(5, message.getReceived());
|
writeBlob(ps, 5, message);
|
||||||
if (message.getStatus() != null)
|
ps.setLong(6, message.getSent());
|
||||||
ps.setString(6, message.getStatus().name());
|
ps.setLong(7, message.getReceived());
|
||||||
else
|
ps.setString(8, message.getStatus() != null ? message.getStatus().name() : null);
|
||||||
ps.setString(6, null);
|
|
||||||
|
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
|
|
||||||
@ -207,11 +210,12 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
|
|
||||||
private void update(Connection connection, Plaintext message) throws SQLException, IOException {
|
private void update(Connection connection, Plaintext message) throws SQLException, IOException {
|
||||||
PreparedStatement ps = connection.prepareStatement(
|
PreparedStatement ps = connection.prepareStatement(
|
||||||
"UPDATE Message SET sent=?, received=?, status=? WHERE id=?");
|
"UPDATE Message SET iv=?, sent=?, received=?, status=? WHERE id=?");
|
||||||
ps.setLong(1, message.getSent());
|
ps.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null);
|
||||||
ps.setLong(2, message.getReceived());
|
ps.setLong(2, message.getSent());
|
||||||
ps.setString(3, message.getStatus() != null ? message.getStatus().name() : null);
|
ps.setLong(3, message.getReceived());
|
||||||
ps.setLong(4, (Long) message.getId());
|
ps.setString(4, message.getStatus() != null ? message.getStatus().name() : null);
|
||||||
|
ps.setLong(5, (Long) message.getId());
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
CREATE TABLE Message (
|
CREATE TABLE Message (
|
||||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
iv BINARY(32) UNIQUE,
|
||||||
|
type VARCHAR(20) NOT NULL,
|
||||||
sender VARCHAR(40) NOT NULL,
|
sender VARCHAR(40) NOT NULL,
|
||||||
recipient VARCHAR(40) NOT NULL,
|
recipient VARCHAR(40),
|
||||||
data BLOB NOT NULL,
|
data BLOB NOT NULL,
|
||||||
sent BIGINT,
|
sent BIGINT,
|
||||||
received BIGINT,
|
received BIGINT,
|
||||||
|
@ -20,16 +20,19 @@ import ch.dissem.bitmessage.BitmessageContext;
|
|||||||
import ch.dissem.bitmessage.InternalContext;
|
import ch.dissem.bitmessage.InternalContext;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.Plaintext;
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
|
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.ports.AddressRepository;
|
import ch.dissem.bitmessage.ports.AddressRepository;
|
||||||
import ch.dissem.bitmessage.ports.MessageRepository;
|
import ch.dissem.bitmessage.ports.MessageRepository;
|
||||||
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
@ -116,7 +119,8 @@ public class JdbcMessageRepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSave() throws Exception {
|
public void testSave() throws Exception {
|
||||||
Plaintext message = new Plaintext.Builder()
|
Plaintext message = new Plaintext.Builder(MSG)
|
||||||
|
.IV(new InventoryVector(Security.randomBytes(32)))
|
||||||
.from(identity)
|
.from(identity)
|
||||||
.to(contactA)
|
.to(contactA)
|
||||||
.message("Subject", "Message")
|
.message("Subject", "Message")
|
||||||
@ -132,6 +136,19 @@ public class JdbcMessageRepositoryTest {
|
|||||||
List<Plaintext> messages = repo.findMessages(Plaintext.Status.DOING_PROOF_OF_WORK);
|
List<Plaintext> messages = repo.findMessages(Plaintext.Status.DOING_PROOF_OF_WORK);
|
||||||
|
|
||||||
assertEquals(1, messages.size());
|
assertEquals(1, messages.size());
|
||||||
|
assertNotNull(messages.get(0).getInventoryVector());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdate() throws Exception {
|
||||||
|
List<Plaintext> messages = repo.findMessages(Plaintext.Status.DRAFT, contactA);
|
||||||
|
Plaintext message = messages.get(0);
|
||||||
|
message.setInventoryVector(new InventoryVector(Security.randomBytes(32)));
|
||||||
|
repo.save(message);
|
||||||
|
|
||||||
|
messages = repo.findMessages(Plaintext.Status.DRAFT, contactA);
|
||||||
|
assertEquals(1, messages.size());
|
||||||
|
assertNotNull(messages.get(0).getInventoryVector());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -143,7 +160,7 @@ public class JdbcMessageRepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addMessage(BitmessageAddress from, BitmessageAddress to, Plaintext.Status status, Label... labels) {
|
private void addMessage(BitmessageAddress from, BitmessageAddress to, Plaintext.Status status, Label... labels) {
|
||||||
Plaintext message = new Plaintext.Builder()
|
Plaintext message = new Plaintext.Builder(MSG)
|
||||||
.from(from)
|
.from(from)
|
||||||
.to(to)
|
.to(to)
|
||||||
.message("Subject", "Message")
|
.message("Subject", "Message")
|
||||||
|
Loading…
Reference in New Issue
Block a user