A simple command line application (WIP), and a few tests. Unfotrunately, receiving messages doesn't seem to work yet.
This commit is contained in:
parent
648afbbc75
commit
6b3b361aa3
291
demo/src/main/java/ch/dissem/bitmessage/demo/Application.java
Normal file
291
demo/src/main/java/ch/dissem/bitmessage/demo/Application.java
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
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.entity.payload.Pubkey;
|
||||||
|
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 org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple command line Bitmessage application
|
||||||
|
*/
|
||||||
|
public class Application {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(Application.class);
|
||||||
|
private final Scanner scanner;
|
||||||
|
|
||||||
|
private BitmessageContext ctx;
|
||||||
|
|
||||||
|
public Application() {
|
||||||
|
ctx = new BitmessageContext.Builder()
|
||||||
|
.addressRepo(new JdbcAddressRepository())
|
||||||
|
.inventory(new JdbcInventory())
|
||||||
|
.nodeRegistry(new JdbcNodeRegistry())
|
||||||
|
.networkHandler(new NetworkNode())
|
||||||
|
.messageRepo(new JdbcMessageRepository())
|
||||||
|
.port(48444)
|
||||||
|
.streams(1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ctx.startup(new BitmessageContext.Listener() {
|
||||||
|
@Override
|
||||||
|
public void receive(Plaintext plaintext) {
|
||||||
|
try {
|
||||||
|
System.out.println(new String(plaintext.getMessage(), "UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scanner = new Scanner(System.in);
|
||||||
|
|
||||||
|
String command;
|
||||||
|
do {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("available commands:");
|
||||||
|
System.out.println("i) identities");
|
||||||
|
System.out.println("c) contacts");
|
||||||
|
System.out.println("m) messages");
|
||||||
|
System.out.println("e) Exit");
|
||||||
|
|
||||||
|
command = nextCommand();
|
||||||
|
try {
|
||||||
|
switch (command) {
|
||||||
|
case "i": {
|
||||||
|
identities();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "c":
|
||||||
|
contacts();
|
||||||
|
break;
|
||||||
|
case "m":
|
||||||
|
messages();
|
||||||
|
break;
|
||||||
|
case "e":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println("Unknown command. Please try again.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.debug(e.getMessage());
|
||||||
|
}
|
||||||
|
} while (!"e".equals(command));
|
||||||
|
LOG.info("Shutting down client");
|
||||||
|
ctx.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nextCommand() {
|
||||||
|
return scanner.nextLine().trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void identities() {
|
||||||
|
String command;
|
||||||
|
List<BitmessageAddress> identities = ctx.addresses().getIdentities();
|
||||||
|
do {
|
||||||
|
System.out.println();
|
||||||
|
int i = 0;
|
||||||
|
for (BitmessageAddress identity : identities) {
|
||||||
|
i++;
|
||||||
|
System.out.print(i + ") ");
|
||||||
|
if (identity.getAlias() != null) {
|
||||||
|
System.out.println(identity.getAlias() + " (" + identity.getAddress() + ")");
|
||||||
|
} else {
|
||||||
|
System.out.println(identity.getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
System.out.println("You have no identities yet.");
|
||||||
|
}
|
||||||
|
System.out.println("a) create identity");
|
||||||
|
System.out.println("b) back");
|
||||||
|
|
||||||
|
command = nextCommand();
|
||||||
|
switch (command) {
|
||||||
|
case "a":
|
||||||
|
addIdentity();
|
||||||
|
break;
|
||||||
|
case "b":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
int index = Integer.parseInt(command) - 1;
|
||||||
|
address(identities.get(index));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.out.println("Unknown command. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!"b".equals(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addIdentity() {
|
||||||
|
System.out.println();
|
||||||
|
BitmessageAddress identity = ctx.createIdentity(yesNo("would you like a shorter address? This will take some time to calculate."), Pubkey.Feature.DOES_ACK);
|
||||||
|
System.out.println("Please enter an alias for this identity, or an empty string for none");
|
||||||
|
String alias = nextCommand();
|
||||||
|
if (alias.length() > 0) {
|
||||||
|
identity.setAlias(alias);
|
||||||
|
}
|
||||||
|
ctx.addresses().save(identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void contacts() {
|
||||||
|
String command;
|
||||||
|
List<BitmessageAddress> contacts = ctx.addresses().getContacts();
|
||||||
|
do {
|
||||||
|
System.out.println();
|
||||||
|
int i = 0;
|
||||||
|
for (BitmessageAddress contact : contacts) {
|
||||||
|
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 contacts yet.");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("a) add contact");
|
||||||
|
System.out.println("b) back");
|
||||||
|
|
||||||
|
command = nextCommand();
|
||||||
|
switch (command) {
|
||||||
|
case "a":
|
||||||
|
addContact();
|
||||||
|
break;
|
||||||
|
case "b":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
int index = Integer.parseInt(command) - 1;
|
||||||
|
address(contacts.get(index));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
System.out.println("Unknown command. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!"b".equals(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addContact() {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("Please enter the Bitmessage address you want to add");
|
||||||
|
try {
|
||||||
|
BitmessageAddress address = new BitmessageAddress(scanner.nextLine().trim());
|
||||||
|
System.out.println("Please enter an alias for this address, or an empty string for none");
|
||||||
|
String alias = scanner.nextLine().trim();
|
||||||
|
if (alias.length() > 0) {
|
||||||
|
address.setAlias(alias);
|
||||||
|
}
|
||||||
|
ctx.addContact(address);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void address(BitmessageAddress address) {
|
||||||
|
System.out.println();
|
||||||
|
if (address.getAlias() != null)
|
||||||
|
System.out.println(address.getAlias());
|
||||||
|
System.out.println(address.getAddress());
|
||||||
|
System.out.println("Stream: " + address.getStream());
|
||||||
|
System.out.println("Version: " + address.getVersion());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void messages() {
|
||||||
|
String command;
|
||||||
|
List<Plaintext> messages = ctx.messages().findMessages(Plaintext.Status.RECEIVED);
|
||||||
|
do {
|
||||||
|
System.out.println();
|
||||||
|
int i = 0;
|
||||||
|
for (Plaintext message : messages) {
|
||||||
|
i++;
|
||||||
|
System.out.print(i + ") From: " + message.getFrom() + "; Subject: " + message.getSubject());
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
System.out.println("You have no messages.");
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("c) compose message");
|
||||||
|
System.out.println("b) back");
|
||||||
|
|
||||||
|
command = scanner.nextLine().trim();
|
||||||
|
switch (command) {
|
||||||
|
case "c":
|
||||||
|
compose();
|
||||||
|
break;
|
||||||
|
case "b":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
int index = Integer.parseInt(command);
|
||||||
|
show(messages.get(index));
|
||||||
|
} catch (NumberFormatException | IndexOutOfBoundsException e) {
|
||||||
|
System.out.println("Unknown command. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!"b".equalsIgnoreCase(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void show(Plaintext message) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("From: " + message.getFrom());
|
||||||
|
System.out.println("To: " + message.getTo());
|
||||||
|
System.out.println("Subject: " + message.getSubject());
|
||||||
|
System.out.println();
|
||||||
|
System.out.println(message.getText());
|
||||||
|
System.out.println();
|
||||||
|
String command;
|
||||||
|
do {
|
||||||
|
System.out.printf("r) reply");
|
||||||
|
System.out.println("d) delete");
|
||||||
|
System.out.printf("b) back");
|
||||||
|
command = nextCommand();
|
||||||
|
switch (command) {
|
||||||
|
case "r":
|
||||||
|
compose(message.getTo(), message.getFrom(), "RE: " + message.getSubject());
|
||||||
|
break;
|
||||||
|
case "d":
|
||||||
|
ctx.messages().remove(message);
|
||||||
|
case "b":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
System.out.println("Unknown command. Please try again.");
|
||||||
|
}
|
||||||
|
} while (!"b".equalsIgnoreCase(command));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compose() {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("TODO");
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compose(BitmessageAddress from, BitmessageAddress to, String subject) {
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("TODO");
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean yesNo(String question) {
|
||||||
|
String answer;
|
||||||
|
do {
|
||||||
|
System.out.println(question + " (y/n)");
|
||||||
|
answer = scanner.nextLine();
|
||||||
|
if ("y".equalsIgnoreCase(answer)) return true;
|
||||||
|
if ("n".equalsIgnoreCase(answer)) return false;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
}
|
@ -18,11 +18,12 @@ package ch.dissem.bitmessage.demo;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.BitmessageContext;
|
import ch.dissem.bitmessage.BitmessageContext;
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
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.JdbcAddressRepository;
|
||||||
import ch.dissem.bitmessage.repository.JdbcInventory;
|
import ch.dissem.bitmessage.repository.JdbcInventory;
|
||||||
import ch.dissem.bitmessage.repository.JdbcMessageRepository;
|
import ch.dissem.bitmessage.repository.JdbcMessageRepository;
|
||||||
import ch.dissem.bitmessage.repository.JdbcNodeRegistry;
|
import ch.dissem.bitmessage.repository.JdbcNodeRegistry;
|
||||||
import ch.dissem.bitmessage.networking.NetworkNode;
|
|
||||||
import ch.dissem.bitmessage.utils.Base58;
|
import ch.dissem.bitmessage.utils.Base58;
|
||||||
import ch.dissem.bitmessage.utils.Encode;
|
import ch.dissem.bitmessage.utils.Encode;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
@ -31,48 +32,18 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
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.
|
* Created by chris on 06.04.15.
|
||||||
*/
|
*/
|
||||||
public class Main {
|
public class Main {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(Main.class);
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
final BitmessageAddress address = new BitmessageAddress("BM-87hJ99tPAXxtetvnje7Z491YSvbEtBJVc5e");
|
final BitmessageAddress address = new BitmessageAddress("BM-87hJ99tPAXxtetvnje7Z491YSvbEtBJVc5e");
|
||||||
|
|
||||||
BitmessageContext ctx = new BitmessageContext.Builder()
|
new Application();
|
||||||
.addressRepo(new JdbcAddressRepository())
|
|
||||||
.inventory(new JdbcInventory())
|
|
||||||
.nodeRegistry(new JdbcNodeRegistry())
|
|
||||||
.networkHandler(new NetworkNode())
|
|
||||||
.messageRepo(new JdbcMessageRepository())
|
|
||||||
.port(48444)
|
|
||||||
.streams(1)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// ctx.startup(new BitmessageContext.Listener() {
|
|
||||||
// @Override
|
|
||||||
// public void receive(Plaintext plaintext) {
|
|
||||||
// // TODO
|
|
||||||
// try {
|
|
||||||
// System.out.println(new String(plaintext.getMessage(), "UTF-8"));
|
|
||||||
// } catch (UnsupportedEncodingException e) {
|
|
||||||
// LOG.error(e.getMessage(), e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
// Scanner scanner = new Scanner(System.in);
|
|
||||||
//// System.out.println("Press Enter to request pubkey for address " + address);
|
|
||||||
//// scanner.nextLine();
|
|
||||||
//// ctx.send(1, address.getVersion(), new GetPubkey(address), 3000, 1000, 1000);
|
|
||||||
//
|
|
||||||
// System.out.println("Press Enter to exit");
|
|
||||||
// scanner.nextLine();
|
|
||||||
// LOG.info("Shutting down client");
|
|
||||||
// ctx.shutdown();
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// List<ObjectMessage> objects = new JdbcInventory().getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY);
|
// List<ObjectMessage> objects = new JdbcInventory().getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY);
|
||||||
|
@ -17,16 +17,17 @@
|
|||||||
package ch.dissem.bitmessage;
|
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.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.Plaintext.Encoding;
|
||||||
import ch.dissem.bitmessage.entity.payload.GetPubkey;
|
import ch.dissem.bitmessage.entity.payload.GetPubkey;
|
||||||
import ch.dissem.bitmessage.entity.payload.Msg;
|
import ch.dissem.bitmessage.entity.payload.Msg;
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
|
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.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.ports.*;
|
import ch.dissem.bitmessage.ports.*;
|
||||||
|
import ch.dissem.bitmessage.ports.NetworkHandler.MessageListener;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
import ch.dissem.bitmessage.utils.UnixTime;
|
import ch.dissem.bitmessage.utils.UnixTime;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -34,10 +35,12 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
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.payload.ObjectType.GET_PUBKEY;
|
||||||
|
import static ch.dissem.bitmessage.entity.payload.ObjectType.MSG;
|
||||||
|
import static ch.dissem.bitmessage.entity.payload.ObjectType.PUBKEY;
|
||||||
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
|
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,8 +56,12 @@ public class BitmessageContext {
|
|||||||
ctx = new InternalContext(builder);
|
ctx = new InternalContext(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BitmessageAddress> getIdentities() {
|
public AddressRepository addresses() {
|
||||||
return ctx.getAddressRepo().getIdentities();
|
return ctx.getAddressRepo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageRepository messages() {
|
||||||
|
return ctx.getMessageRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitmessageAddress createIdentity(boolean shorter, Feature... features) {
|
public BitmessageAddress createIdentity(boolean shorter, Feature... features) {
|
||||||
@ -66,6 +73,7 @@ public class BitmessageContext {
|
|||||||
features
|
features
|
||||||
));
|
));
|
||||||
ctx.getAddressRepo().save(identity);
|
ctx.getAddressRepo().save(identity);
|
||||||
|
ctx.sendPubkey(identity, identity.getStream());
|
||||||
return identity;
|
return identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,13 +142,23 @@ public class BitmessageContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startup(Listener listener) {
|
public void startup(Listener listener) {
|
||||||
ctx.getNetworkHandler().start(new DefaultMessageListener(ctx, listener));
|
MessageListener messageListener = new DefaultMessageListener(ctx, listener);
|
||||||
|
for (ObjectMessage object : ctx.getInventory().getObjects(0, 0, PUBKEY, MSG)) {
|
||||||
|
messageListener.receive(object);
|
||||||
|
}
|
||||||
|
ctx.getNetworkHandler().start(messageListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
ctx.getNetworkHandler().stop();
|
ctx.getNetworkHandler().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addContact(BitmessageAddress contact) {
|
||||||
|
ctx.getAddressRepo().save(contact);
|
||||||
|
// TODO: search pubkey in inventory
|
||||||
|
ctx.requestPubkey(contact);
|
||||||
|
}
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void receive(Plaintext plaintext);
|
void receive(Plaintext plaintext);
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,10 @@
|
|||||||
package ch.dissem.bitmessage;
|
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.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
import ch.dissem.bitmessage.entity.Plaintext;
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
import ch.dissem.bitmessage.entity.payload.*;
|
import ch.dissem.bitmessage.entity.payload.*;
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler;
|
import ch.dissem.bitmessage.ports.NetworkHandler;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
|
||||||
import ch.dissem.bitmessage.utils.UnixTime;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -47,6 +44,8 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
@Override
|
@Override
|
||||||
public void receive(ObjectMessage object) {
|
public void receive(ObjectMessage object) {
|
||||||
ObjectPayload payload = object.getPayload();
|
ObjectPayload payload = object.getPayload();
|
||||||
|
if (payload.getType() == null) return;
|
||||||
|
|
||||||
switch (payload.getType()) {
|
switch (payload.getType()) {
|
||||||
case GET_PUBKEY: {
|
case GET_PUBKEY: {
|
||||||
receive(object, (GetPubkey) payload);
|
receive(object, (GetPubkey) payload);
|
||||||
@ -70,28 +69,8 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
protected void receive(ObjectMessage object, GetPubkey getPubkey) {
|
protected void receive(ObjectMessage object, GetPubkey getPubkey) {
|
||||||
BitmessageAddress identity = ctx.getAddressRepo().findIdentity(getPubkey.getRipeTag());
|
BitmessageAddress identity = ctx.getAddressRepo().findIdentity(getPubkey.getRipeTag());
|
||||||
if (identity != null && identity.getPrivateKey() != null) {
|
if (identity != null && identity.getPrivateKey() != null) {
|
||||||
try {
|
LOG.debug("Got pubkey request for identity " + identity);
|
||||||
long expires = UnixTime.now(+28 * DAY);
|
ctx.sendPubkey(identity, object.getStream());
|
||||||
LOG.info("Expires at " + expires);
|
|
||||||
ObjectMessage response = new ObjectMessage.Builder()
|
|
||||||
.stream(object.getStream())
|
|
||||||
.version(identity.getVersion())
|
|
||||||
.expiresTime(expires)
|
|
||||||
.payload(identity.getPubkey())
|
|
||||||
.build();
|
|
||||||
Security.doProofOfWork(response, ctx.getProofOfWorkEngine(),
|
|
||||||
ctx.getNetworkNonceTrialsPerByte(), ctx.getNetworkExtraBytes());
|
|
||||||
if (response.isSigned()) {
|
|
||||||
response.sign(identity.getPrivateKey());
|
|
||||||
}
|
|
||||||
if (response instanceof Encrypted) {
|
|
||||||
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
|
|
||||||
}
|
|
||||||
ctx.getInventory().storeObject(response);
|
|
||||||
ctx.getNetworkHandler().offer(response.getInventoryVector());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,8 +88,9 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
}
|
}
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
address.setPubkey(pubkey);
|
address.setPubkey(pubkey);
|
||||||
|
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);
|
||||||
for (Plaintext msg:messages){
|
for (Plaintext msg : messages) {
|
||||||
// TODO: send messages enqueued for this address
|
// 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);
|
||||||
@ -140,7 +120,7 @@ class DefaultMessageListener implements NetworkHandler.MessageListener {
|
|||||||
ctx.getMessageRepository().save(msg.getPlaintext());
|
ctx.getMessageRepository().save(msg.getPlaintext());
|
||||||
listener.receive(msg.getPlaintext());
|
listener.receive(msg.getPlaintext());
|
||||||
break;
|
break;
|
||||||
} catch (IOException ignore) {
|
} catch (IOException | RuntimeException ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ 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.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.*;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
@ -29,6 +30,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The internal context should normally only be used for port implementations. If you need it in your client
|
* The internal context should normally only be used for port implementations. If you need it in your client
|
||||||
* implementation, you're either doing something wrong, something very weird, or the BitmessageContext should
|
* implementation, you're either doing something wrong, something very weird, or the BitmessageContext should
|
||||||
@ -160,6 +163,51 @@ public class InternalContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendPubkey(BitmessageAddress identity, long targetStream) {
|
||||||
|
try {
|
||||||
|
long expires = UnixTime.now(+28 * DAY);
|
||||||
|
LOG.info("Expires at " + expires);
|
||||||
|
ObjectMessage response = new ObjectMessage.Builder()
|
||||||
|
.stream(targetStream)
|
||||||
|
.version(identity.getVersion())
|
||||||
|
.expiresTime(expires)
|
||||||
|
.payload(identity.getPubkey())
|
||||||
|
.build();
|
||||||
|
response.sign(identity.getPrivateKey());
|
||||||
|
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
|
||||||
|
Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes);
|
||||||
|
if (response.isSigned()) {
|
||||||
|
response.sign(identity.getPrivateKey());
|
||||||
|
}
|
||||||
|
if (response instanceof Encrypted) {
|
||||||
|
response.encrypt(Security.createPublicKey(identity.getPubkeyDecryptionKey()).getEncoded(false));
|
||||||
|
}
|
||||||
|
inventory.storeObject(response);
|
||||||
|
networkHandler.offer(response.getInventoryVector());
|
||||||
|
// TODO: save that the pubkey was just sent, and on which stream!
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestPubkey(BitmessageAddress contact) {
|
||||||
|
try {
|
||||||
|
long expires = UnixTime.now(+2 * DAY);
|
||||||
|
LOG.info("Expires at " + expires);
|
||||||
|
ObjectMessage response = new ObjectMessage.Builder()
|
||||||
|
.stream(contact.getStream())
|
||||||
|
.version(contact.getVersion())
|
||||||
|
.expiresTime(expires)
|
||||||
|
.payload(new GetPubkey(contact))
|
||||||
|
.build();
|
||||||
|
Security.doProofOfWork(response, proofOfWorkEngine, networkNonceTrialsPerByte, networkExtraBytes);
|
||||||
|
inventory.storeObject(response);
|
||||||
|
networkHandler.offer(response.getInventoryVector());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface ContextHolder {
|
public interface ContextHolder {
|
||||||
void setContext(InternalContext context);
|
void setContext(InternalContext context);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static ch.dissem.bitmessage.utils.Decode.bytes;
|
import static ch.dissem.bitmessage.utils.Decode.bytes;
|
||||||
import static ch.dissem.bitmessage.utils.Decode.varInt;
|
import static ch.dissem.bitmessage.utils.Decode.varInt;
|
||||||
@ -180,4 +181,19 @@ public class BitmessageAddress {
|
|||||||
public byte[] getTag() {
|
public byte[] getTag() {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
BitmessageAddress address = (BitmessageAddress) o;
|
||||||
|
return Objects.equals(version, address.version) &&
|
||||||
|
Objects.equals(stream, address.stream) &&
|
||||||
|
Arrays.equals(ripe, address.ripe);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(ripe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,15 +60,15 @@ public class NetworkMessage implements Streamable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(OutputStream stream) throws IOException {
|
public void write(OutputStream out) throws IOException {
|
||||||
// magic
|
// magic
|
||||||
Encode.int32(MAGIC, stream);
|
Encode.int32(MAGIC, out);
|
||||||
|
|
||||||
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
|
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
|
||||||
String command = payload.getCommand().name().toLowerCase();
|
String command = payload.getCommand().name().toLowerCase();
|
||||||
stream.write(command.getBytes("ASCII"));
|
out.write(command.getBytes("ASCII"));
|
||||||
for (int i = command.length(); i < 12; i++) {
|
for (int i = command.length(); i < 12; i++) {
|
||||||
stream.write('\0');
|
out.write('\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream payloadStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream payloadStream = new ByteArrayOutputStream();
|
||||||
@ -78,16 +78,16 @@ public class NetworkMessage implements Streamable {
|
|||||||
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
|
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
|
||||||
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
|
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
|
||||||
// larger than this.
|
// larger than this.
|
||||||
Encode.int32(payloadBytes.length, stream);
|
Encode.int32(payloadBytes.length, out);
|
||||||
|
|
||||||
// checksum
|
// checksum
|
||||||
try {
|
try {
|
||||||
stream.write(getChecksum(payloadBytes));
|
out.write(getChecksum(payloadBytes));
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// message payload
|
// message payload
|
||||||
stream.write(payloadBytes);
|
out.write(payloadBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,7 @@ import ch.dissem.bitmessage.factory.Factory;
|
|||||||
import ch.dissem.bitmessage.utils.Decode;
|
import ch.dissem.bitmessage.utils.Decode;
|
||||||
import ch.dissem.bitmessage.utils.Encode;
|
import ch.dissem.bitmessage.utils.Encode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,8 +118,8 @@ public class Plaintext implements Streamable {
|
|||||||
Encode.varInt(from.getVersion(), out);
|
Encode.varInt(from.getVersion(), out);
|
||||||
Encode.varInt(from.getStream(), out);
|
Encode.varInt(from.getStream(), out);
|
||||||
Encode.int32(from.getPubkey().getBehaviorBitfield(), out);
|
Encode.int32(from.getPubkey().getBehaviorBitfield(), out);
|
||||||
out.write(from.getPubkey().getSigningKey());
|
out.write(from.getPubkey().getSigningKey(), 1, 64);
|
||||||
out.write(from.getPubkey().getEncryptionKey());
|
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());
|
out.write(to.getRipe());
|
||||||
@ -167,6 +164,30 @@ public class Plaintext implements Streamable {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSubject() {
|
||||||
|
Scanner s = new Scanner(new ByteArrayInputStream(message), "UTF-8");
|
||||||
|
String firstLine = s.nextLine();
|
||||||
|
if (encoding == 2) {
|
||||||
|
return firstLine.substring("Subject:".length()).trim();
|
||||||
|
} else if (firstLine.length() > 50) {
|
||||||
|
return firstLine.substring(0, 50).trim() + "...";
|
||||||
|
} else {
|
||||||
|
return firstLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
try {
|
||||||
|
String text = new String(message, "UTF-8");
|
||||||
|
if (encoding == 2) {
|
||||||
|
return text.substring(text.indexOf("\nBody:") + 6);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum Encoding {
|
public enum Encoding {
|
||||||
IGNORE(0), TRIVIAL(1), SIMPLE(2);
|
IGNORE(0), TRIVIAL(1), SIMPLE(2);
|
||||||
|
|
||||||
@ -176,23 +197,21 @@ public class Plaintext implements Streamable {
|
|||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Encoding fromCode(long code) {
|
|
||||||
for (Encoding e : values()) {
|
|
||||||
if (e.getCode() == code) return e;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCode() {
|
public long getCode() {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Status {
|
public enum Status {
|
||||||
|
// For sent messages
|
||||||
PUBKEY_REQUESTED,
|
PUBKEY_REQUESTED,
|
||||||
DOING_PROOF_OF_WORK,
|
DOING_PROOF_OF_WORK,
|
||||||
SENT,
|
SENT,
|
||||||
ACKNOWLEDGED
|
SENT_ACKNOWLEDGED,
|
||||||
|
|
||||||
|
// For received messages
|
||||||
|
RECEIVED,
|
||||||
|
READ
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
@ -340,7 +359,7 @@ public class Plaintext implements Streamable {
|
|||||||
publicEncryptionKey,
|
publicEncryptionKey,
|
||||||
nonceTrialsPerByte,
|
nonceTrialsPerByte,
|
||||||
extraBytes,
|
extraBytes,
|
||||||
Pubkey.Feature.features(behaviorBitfield)
|
behaviorBitfield
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (to == null) {
|
if (to == null) {
|
||||||
@ -349,4 +368,26 @@ public class Plaintext implements Streamable {
|
|||||||
return new Plaintext(this);
|
return new Plaintext(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Plaintext plaintext = (Plaintext) o;
|
||||||
|
return Objects.equals(encoding, plaintext.encoding) &&
|
||||||
|
Objects.equals(from, plaintext.from) &&
|
||||||
|
Arrays.equals(message, plaintext.message) &&
|
||||||
|
Arrays.equals(ack, plaintext.ack) &&
|
||||||
|
Arrays.equals(to.getRipe(), plaintext.to.getRipe()) &&
|
||||||
|
Arrays.equals(signature, plaintext.signature) &&
|
||||||
|
Objects.equals(status, plaintext.status) &&
|
||||||
|
Objects.equals(sent, plaintext.sent) &&
|
||||||
|
Objects.equals(received, plaintext.received) &&
|
||||||
|
Objects.equals(labels, plaintext.labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(from, encoding, message, ack, to, signature, status, sent, received, labels);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,16 +28,17 @@ import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
|
|||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
import org.bouncycastle.crypto.params.ParametersWithIV;
|
import org.bouncycastle.crypto.params.ParametersWithIV;
|
||||||
import org.bouncycastle.math.ec.ECPoint;
|
import org.bouncycastle.math.ec.ECPoint;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by chris on 09.04.15.
|
|
||||||
*/
|
|
||||||
public class CryptoBox implements Streamable {
|
public class CryptoBox implements Streamable {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CryptoBox.class);
|
||||||
|
|
||||||
private final byte[] initializationVector;
|
private final byte[] initializationVector;
|
||||||
private final int curveType;
|
private final int curveType;
|
||||||
private final ECPoint R;
|
private final ECPoint R;
|
||||||
@ -182,7 +183,7 @@ public class CryptoBox implements Streamable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Builder curveType(int curveType) {
|
public Builder curveType(int curveType) {
|
||||||
if (curveType != 0x2CA) System.out.println("Unexpected curve type " + curveType);
|
if (curveType != 0x2CA) LOG.debug("Unexpected curve type " + curveType);
|
||||||
this.curveType = curveType;
|
this.curveType = curveType;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload;
|
package ch.dissem.bitmessage.entity.payload;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static ch.dissem.bitmessage.utils.Security.ripemd160;
|
import static ch.dissem.bitmessage.utils.Security.ripemd160;
|
||||||
@ -51,6 +53,10 @@ public abstract class Pubkey extends ObjectPayload {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeUnencrypted(OutputStream out) throws IOException {
|
||||||
|
write(out);
|
||||||
|
}
|
||||||
|
|
||||||
protected byte[] add0x04(byte[] key) {
|
protected byte[] add0x04(byte[] key) {
|
||||||
if (key.length == 65) return key;
|
if (key.length == 65) return key;
|
||||||
byte[] result = new byte[65];
|
byte[] result = new byte[65];
|
||||||
|
@ -22,6 +22,8 @@ import ch.dissem.bitmessage.utils.Encode;
|
|||||||
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 java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A version 3 public key.
|
* A version 3 public key.
|
||||||
@ -100,7 +102,7 @@ public class V3Pubkey extends V2Pubkey {
|
|||||||
private byte[] publicEncryptionKey;
|
private byte[] publicEncryptionKey;
|
||||||
private long nonceTrialsPerByte;
|
private long nonceTrialsPerByte;
|
||||||
private long extraBytes;
|
private long extraBytes;
|
||||||
private byte[] signature;
|
private byte[] signature = new byte[0];
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
}
|
}
|
||||||
@ -144,4 +146,22 @@ public class V3Pubkey extends V2Pubkey {
|
|||||||
return new V3Pubkey(this);
|
return new V3Pubkey(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
V3Pubkey pubkey = (V3Pubkey) o;
|
||||||
|
return Objects.equals(nonceTrialsPerByte, pubkey.nonceTrialsPerByte) &&
|
||||||
|
Objects.equals(extraBytes, pubkey.extraBytes) &&
|
||||||
|
stream == pubkey.stream &&
|
||||||
|
behaviorBitfield == pubkey.behaviorBitfield &&
|
||||||
|
Arrays.equals(publicSigningKey, pubkey.publicSigningKey) &&
|
||||||
|
Arrays.equals(publicEncryptionKey, pubkey.publicEncryptionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(nonceTrialsPerByte, extraBytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import ch.dissem.bitmessage.utils.Decode;
|
|||||||
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 java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A version 4 public key. When version 4 pubkeys are created, most of the data in the pubkey is encrypted. This is
|
* A version 4 public key. When version 4 pubkeys are created, most of the data in the pubkey is encrypted. This is
|
||||||
@ -43,15 +44,18 @@ public class V4Pubkey extends Pubkey implements Encrypted {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public V4Pubkey(V3Pubkey decrypted) {
|
public V4Pubkey(V3Pubkey decrypted) {
|
||||||
|
this.decrypted = decrypted;
|
||||||
this.stream = decrypted.stream;
|
this.stream = decrypted.stream;
|
||||||
this.tag = BitmessageAddress.calculateTag(4, decrypted.getStream(), decrypted.getRipe());
|
this.tag = BitmessageAddress.calculateTag(4, decrypted.getStream(), decrypted.getRipe());
|
||||||
this.decrypted = decrypted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static V4Pubkey read(InputStream in, long stream, int length) throws IOException {
|
public static V4Pubkey read(InputStream in, long stream, int length, boolean encrypted) throws IOException {
|
||||||
return new V4Pubkey(stream,
|
if (encrypted)
|
||||||
Decode.bytes(in, 32),
|
return new V4Pubkey(stream,
|
||||||
CryptoBox.read(in, length - 32));
|
Decode.bytes(in, 32),
|
||||||
|
CryptoBox.read(in, length - 32));
|
||||||
|
else
|
||||||
|
return new V4Pubkey(V3Pubkey.read(in, stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -76,6 +80,11 @@ public class V4Pubkey extends Pubkey implements Encrypted {
|
|||||||
encrypted.write(stream);
|
encrypted.write(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeUnencrypted(OutputStream out) throws IOException {
|
||||||
|
decrypted.write(out);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeBytesToSign(OutputStream out) throws IOException {
|
public void writeBytesToSign(OutputStream out) throws IOException {
|
||||||
out.write(tag);
|
out.write(tag);
|
||||||
@ -141,4 +150,25 @@ public class V4Pubkey extends Pubkey implements Encrypted {
|
|||||||
public long getExtraBytes() {
|
public long getExtraBytes() {
|
||||||
return decrypted.getExtraBytes();
|
return decrypted.getExtraBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
V4Pubkey v4Pubkey = (V4Pubkey) o;
|
||||||
|
|
||||||
|
if (stream != v4Pubkey.stream) return false;
|
||||||
|
if (!Arrays.equals(tag, v4Pubkey.tag)) return false;
|
||||||
|
return !(decrypted != null ? !decrypted.equals(v4Pubkey.decrypted) : v4Pubkey.decrypted != null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = (int) (stream ^ (stream >>> 32));
|
||||||
|
result = 31 * result + Arrays.hashCode(tag);
|
||||||
|
result = 31 * result + (decrypted != null ? decrypted.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ package ch.dissem.bitmessage.entity.valueobject;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.Streamable;
|
import ch.dissem.bitmessage.entity.Streamable;
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.utils.Bytes;
|
import ch.dissem.bitmessage.utils.Bytes;
|
||||||
import ch.dissem.bitmessage.utils.Decode;
|
import ch.dissem.bitmessage.utils.Decode;
|
||||||
@ -76,7 +78,7 @@ public class PrivateKey implements Streamable {
|
|||||||
int version = (int) Decode.varInt(is);
|
int version = (int) Decode.varInt(is);
|
||||||
long stream = Decode.varInt(is);
|
long stream = Decode.varInt(is);
|
||||||
int len = (int) Decode.varInt(is);
|
int len = (int) Decode.varInt(is);
|
||||||
Pubkey pubkey = Factory.readPubkey(version, stream, is, len);
|
Pubkey pubkey = Factory.readPubkey(version, stream, is, len, false);
|
||||||
len = (int) Decode.varInt(is);
|
len = (int) Decode.varInt(is);
|
||||||
byte[] signingKey = Decode.bytes(is, len);
|
byte[] signingKey = Decode.bytes(is, len);
|
||||||
len = (int) Decode.varInt(is);
|
len = (int) Decode.varInt(is);
|
||||||
@ -97,16 +99,16 @@ public class PrivateKey implements Streamable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(OutputStream os) throws IOException {
|
public void write(OutputStream out) throws IOException {
|
||||||
Encode.varInt(pubkey.getVersion(), os);
|
Encode.varInt(pubkey.getVersion(), out);
|
||||||
Encode.varInt(pubkey.getStream(), os);
|
Encode.varInt(pubkey.getStream(), out);
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
pubkey.write(baos);
|
pubkey.writeUnencrypted(baos);
|
||||||
Encode.varInt(baos.size(), os);
|
Encode.varInt(baos.size(), out);
|
||||||
os.write(baos.toByteArray());
|
out.write(baos.toByteArray());
|
||||||
Encode.varInt(privateSigningKey.length, os);
|
Encode.varInt(privateSigningKey.length, out);
|
||||||
os.write(privateSigningKey);
|
out.write(privateSigningKey);
|
||||||
Encode.varInt(privateEncryptionKey.length, os);
|
Encode.varInt(privateEncryptionKey.length, out);
|
||||||
os.write(privateEncryptionKey);
|
out.write(privateEncryptionKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,12 @@ public class Factory {
|
|||||||
|
|
||||||
public static Pubkey createPubkey(long version, long stream, byte[] publicSigningKey, byte[] publicEncryptionKey,
|
public static Pubkey createPubkey(long version, long stream, byte[] publicSigningKey, byte[] publicEncryptionKey,
|
||||||
long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
||||||
|
return createPubkey(version, stream, publicSigningKey, publicEncryptionKey, nonceTrialsPerByte, extraBytes,
|
||||||
|
Pubkey.Feature.bitfield(features));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pubkey createPubkey(long version, long stream, byte[] publicSigningKey, byte[] publicEncryptionKey,
|
||||||
|
long nonceTrialsPerByte, long extraBytes, int behaviourBitfield) {
|
||||||
if (publicSigningKey.length != 64 && publicSigningKey.length != 65)
|
if (publicSigningKey.length != 64 && publicSigningKey.length != 65)
|
||||||
throw new IllegalArgumentException("64 bytes signing key expected, but it was "
|
throw new IllegalArgumentException("64 bytes signing key expected, but it was "
|
||||||
+ publicSigningKey.length + " bytes long.");
|
+ publicSigningKey.length + " bytes long.");
|
||||||
@ -69,14 +75,14 @@ public class Factory {
|
|||||||
.stream(stream)
|
.stream(stream)
|
||||||
.publicSigningKey(publicSigningKey)
|
.publicSigningKey(publicSigningKey)
|
||||||
.publicEncryptionKey(publicEncryptionKey)
|
.publicEncryptionKey(publicEncryptionKey)
|
||||||
.behaviorBitfield(Pubkey.Feature.bitfield(features))
|
.behaviorBitfield(behaviourBitfield)
|
||||||
.build();
|
.build();
|
||||||
case 3:
|
case 3:
|
||||||
return new V3Pubkey.Builder()
|
return new V3Pubkey.Builder()
|
||||||
.stream(stream)
|
.stream(stream)
|
||||||
.publicSigningKey(publicSigningKey)
|
.publicSigningKey(publicSigningKey)
|
||||||
.publicEncryptionKey(publicEncryptionKey)
|
.publicEncryptionKey(publicEncryptionKey)
|
||||||
.behaviorBitfield(Pubkey.Feature.bitfield(features))
|
.behaviorBitfield(behaviourBitfield)
|
||||||
.nonceTrialsPerByte(nonceTrialsPerByte)
|
.nonceTrialsPerByte(nonceTrialsPerByte)
|
||||||
.extraBytes(extraBytes)
|
.extraBytes(extraBytes)
|
||||||
.build();
|
.build();
|
||||||
@ -86,7 +92,7 @@ public class Factory {
|
|||||||
.stream(stream)
|
.stream(stream)
|
||||||
.publicSigningKey(publicSigningKey)
|
.publicSigningKey(publicSigningKey)
|
||||||
.publicEncryptionKey(publicEncryptionKey)
|
.publicEncryptionKey(publicEncryptionKey)
|
||||||
.behaviorBitfield(Pubkey.Feature.bitfield(features))
|
.behaviorBitfield(behaviourBitfield)
|
||||||
.nonceTrialsPerByte(nonceTrialsPerByte)
|
.nonceTrialsPerByte(nonceTrialsPerByte)
|
||||||
.extraBytes(extraBytes)
|
.extraBytes(extraBytes)
|
||||||
.build()
|
.build()
|
||||||
@ -125,21 +131,21 @@ public class Factory {
|
|||||||
return GetPubkey.read(stream, streamNumber, length, version);
|
return GetPubkey.read(stream, streamNumber, length, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pubkey readPubkey(long version, long stream, InputStream is, int length) throws IOException {
|
public static Pubkey readPubkey(long version, long stream, InputStream is, int length, boolean encrypted) throws IOException {
|
||||||
switch ((int) version) {
|
switch ((int) version) {
|
||||||
case 2:
|
case 2:
|
||||||
return V2Pubkey.read(is, stream);
|
return V2Pubkey.read(is, stream);
|
||||||
case 3:
|
case 3:
|
||||||
return V3Pubkey.read(is, stream);
|
return V3Pubkey.read(is, stream);
|
||||||
case 4:
|
case 4:
|
||||||
return V4Pubkey.read(is, stream, length);
|
return V4Pubkey.read(is, stream, length, encrypted);
|
||||||
}
|
}
|
||||||
LOG.debug("Unexpected pubkey version " + version + ", handling as generic payload object");
|
LOG.debug("Unexpected pubkey version " + version + ", handling as generic payload object");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectPayload parsePubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
private static ObjectPayload parsePubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
Pubkey pubkey = readPubkey(version, streamNumber, stream, length);
|
Pubkey pubkey = readPubkey(version, streamNumber, stream, length, true);
|
||||||
return pubkey != null ? pubkey : GenericPayload.read(stream, streamNumber, length);
|
return pubkey != null ? pubkey : GenericPayload.read(stream, streamNumber, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ public interface Inventory {
|
|||||||
|
|
||||||
ObjectMessage getObject(InventoryVector vector);
|
ObjectMessage getObject(InventoryVector vector);
|
||||||
|
|
||||||
List<ObjectMessage> getObjects(long stream, long version, ObjectType type);
|
List<ObjectMessage> getObjects(long stream, long version, ObjectType... types);
|
||||||
|
|
||||||
void storeObject(ObjectMessage object);
|
void storeObject(ObjectMessage object);
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.utils;
|
package ch.dissem.bitmessage.utils;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.*;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
|
import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
|
||||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
@ -35,6 +35,7 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
import java.security.PrivateKey;
|
||||||
import java.security.spec.KeySpec;
|
import java.security.spec.KeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.utils;
|
package ch.dissem.bitmessage.utils;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by chris on 13.04.15.
|
* Created by chris on 13.04.15.
|
||||||
*/
|
*/
|
||||||
@ -38,6 +40,15 @@ public class Strings {
|
|||||||
return streamList;
|
return streamList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static StringBuilder join(ObjectType... types) {
|
||||||
|
StringBuilder streamList = new StringBuilder();
|
||||||
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
if (i > 0) streamList.append(", ");
|
||||||
|
streamList.append(types[i].getNumber());
|
||||||
|
}
|
||||||
|
return streamList;
|
||||||
|
}
|
||||||
|
|
||||||
public static StringBuilder join(Object... objects) {
|
public static StringBuilder join(Object... objects) {
|
||||||
StringBuilder streamList = new StringBuilder();
|
StringBuilder streamList = new StringBuilder();
|
||||||
for (int i = 0; i < objects.length; i++) {
|
for (int i = 0; i < objects.length; i++) {
|
||||||
|
@ -16,21 +16,23 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage;
|
package ch.dissem.bitmessage;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.Plaintext;
|
||||||
import ch.dissem.bitmessage.entity.payload.CryptoBox;
|
import ch.dissem.bitmessage.entity.payload.CryptoBox;
|
||||||
import ch.dissem.bitmessage.entity.payload.GenericPayload;
|
import ch.dissem.bitmessage.entity.payload.GenericPayload;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Msg;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
import org.junit.Ignore;
|
import ch.dissem.bitmessage.utils.TestUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by chris on 10.05.15.
|
|
||||||
*/
|
|
||||||
public class EncryptionTest {
|
public class EncryptionTest {
|
||||||
@Test
|
@Test
|
||||||
public void ensureDecryptedDataIsSameAsBeforeEncryption() throws IOException {
|
public void ensureDecryptedDataIsSameAsBeforeEncryption() throws IOException {
|
||||||
@ -43,4 +45,19 @@ public class EncryptionTest {
|
|||||||
|
|
||||||
assertEquals(before, after);
|
assertEquals(before, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureMessageCanBeDecrypted() throws IOException {
|
||||||
|
PrivateKey privateKey = PrivateKey.read(TestUtils.getResource("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8.privkey"));
|
||||||
|
BitmessageAddress identity = new BitmessageAddress(privateKey);
|
||||||
|
assertEquals("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8", identity.getAddress());
|
||||||
|
|
||||||
|
ObjectMessage object = TestUtils.loadObjectMessage(3, "V1Msg.payload");
|
||||||
|
Msg msg = (Msg) object.getPayload();
|
||||||
|
msg.decrypt(privateKey.getPrivateEncryptionKey());
|
||||||
|
Plaintext plaintext = msg.getPlaintext();
|
||||||
|
assertNotNull(plaintext);
|
||||||
|
assertEquals("Test", plaintext.getSubject());
|
||||||
|
assertEquals("Hallo, das ist ein Test von der v4-Adresse", plaintext.getText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,19 @@ 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.payload.Msg;
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.utils.TestUtils;
|
import ch.dissem.bitmessage.utils.TestUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class SignatureTest {
|
public class SignatureTest {
|
||||||
@Test
|
@Test
|
||||||
@ -39,7 +43,6 @@ public class SignatureTest {
|
|||||||
@Test
|
@Test
|
||||||
public void ensureSigningWorks() throws IOException {
|
public void ensureSigningWorks() throws IOException {
|
||||||
PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000);
|
PrivateKey privateKey = new PrivateKey(false, 1, 1000, 1000);
|
||||||
BitmessageAddress address = new BitmessageAddress(privateKey);
|
|
||||||
|
|
||||||
ObjectMessage objectMessage = new ObjectMessage.Builder()
|
ObjectMessage objectMessage = new ObjectMessage.Builder()
|
||||||
.objectType(ObjectType.PUBKEY)
|
.objectType(ObjectType.PUBKEY)
|
||||||
@ -51,4 +54,25 @@ public class SignatureTest {
|
|||||||
|
|
||||||
assertTrue(objectMessage.isSignatureValid(privateKey.getPubkey()));
|
assertTrue(objectMessage.isSignatureValid(privateKey.getPubkey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureMessageIsProperlySigned() throws IOException {
|
||||||
|
BitmessageAddress identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8");
|
||||||
|
|
||||||
|
ObjectMessage object = TestUtils.loadObjectMessage(3, "V1Msg.payload");
|
||||||
|
Msg msg = (Msg) object.getPayload();
|
||||||
|
msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey());
|
||||||
|
Plaintext plaintext = msg.getPlaintext();
|
||||||
|
assertEquals(0, object.getExpiresTime());
|
||||||
|
assertEquals(loadPubkey(), plaintext.getFrom().getPubkey());
|
||||||
|
assertNotNull(plaintext);
|
||||||
|
assertTrue(object.isSignatureValid(plaintext.getFrom().getPubkey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private V4Pubkey loadPubkey() throws IOException {
|
||||||
|
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
|
||||||
|
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
|
||||||
|
object.decrypt(address.getPubkeyDecryptionKey());
|
||||||
|
return (V4Pubkey) object.getPayload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package ch.dissem.bitmessage.entity;
|
package ch.dissem.bitmessage.entity;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.utils.*;
|
import ch.dissem.bitmessage.utils.*;
|
||||||
|
@ -75,6 +75,23 @@ public class SerializationTest {
|
|||||||
doTest("V1MsgStrangeData.payload", 1, GenericPayload.class);
|
doTest("V1MsgStrangeData.payload", 1, GenericPayload.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException {
|
||||||
|
Plaintext p1 = new Plaintext.Builder()
|
||||||
|
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
|
||||||
|
.to(TestUtils.loadContact())
|
||||||
|
.encoding(Plaintext.Encoding.SIMPLE)
|
||||||
|
.message("Subject", "Message")
|
||||||
|
.ack("ack".getBytes())
|
||||||
|
.signature(new byte[0])
|
||||||
|
.build();
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
p1.write(out);
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
Plaintext p2 = Plaintext.read(in);
|
||||||
|
assertEquals(p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
private void doTest(String resourceName, int version, Class<?> expectedPayloadType) throws IOException {
|
private void doTest(String resourceName, int version, Class<?> expectedPayloadType) throws IOException {
|
||||||
byte[] data = TestUtils.getBytes(resourceName);
|
byte[] data = TestUtils.getBytes(resourceName);
|
||||||
InputStream in = new ByteArrayInputStream(data);
|
InputStream in = new ByteArrayInputStream(data);
|
||||||
|
@ -25,9 +25,8 @@ import javax.xml.bind.DatatypeConverter;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.utils.UnixTime.DAY;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,7 +71,8 @@ public class SecurityTest {
|
|||||||
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() + 300) // 5 minutes
|
.expiresTime(UnixTime.now(+2 * DAY)) // 5 minutes
|
||||||
|
.objectType(0)
|
||||||
.payload(GenericPayload.read(new ByteArrayInputStream(new byte[0]), 1, 0))
|
.payload(GenericPayload.read(new ByteArrayInputStream(new byte[0]), 1, 0))
|
||||||
.build();
|
.build();
|
||||||
Security.checkProofOfWork(objectMessage, 1000, 1000);
|
Security.checkProofOfWork(objectMessage, 1000, 1000);
|
||||||
@ -80,11 +80,10 @@ public class SecurityTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoProofOfWork() throws IOException {
|
public void testDoProofOfWork() throws IOException {
|
||||||
Calendar expires = new GregorianCalendar();
|
|
||||||
expires.add(1, Calendar.HOUR);
|
|
||||||
ObjectMessage objectMessage = new ObjectMessage.Builder()
|
ObjectMessage objectMessage = new ObjectMessage.Builder()
|
||||||
.nonce(new byte[8])
|
.nonce(new byte[8])
|
||||||
.expiresTime(expires.getTimeInMillis() / 1000)
|
.expiresTime(UnixTime.now(+2 * DAY))
|
||||||
|
.objectType(0)
|
||||||
.payload(GenericPayload.read(new ByteArrayInputStream(new byte[0]), 1, 0))
|
.payload(GenericPayload.read(new ByteArrayInputStream(new byte[0]), 1, 0))
|
||||||
.build();
|
.build();
|
||||||
Security.doProofOfWork(objectMessage, new MultiThreadedPOWEngine(), 1000, 1000);
|
Security.doProofOfWork(objectMessage, new MultiThreadedPOWEngine(), 1000, 1000);
|
||||||
|
@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.utils;
|
package ch.dissem.bitmessage.utils;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -24,6 +27,8 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there's ever a need for this in production code, it should be rewritten to be more efficient.
|
* If there's ever a need for this in production code, it should be rewritten to be more efficient.
|
||||||
*/
|
*/
|
||||||
@ -51,4 +56,23 @@ public class TestUtils {
|
|||||||
}
|
}
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static InputStream getResource(String resourceName) {
|
||||||
|
return TestUtils.class.getClassLoader().getResourceAsStream(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BitmessageAddress loadIdentity(String address) throws IOException {
|
||||||
|
PrivateKey privateKey = PrivateKey.read(TestUtils.getResource(address + ".privkey"));
|
||||||
|
BitmessageAddress identity = new BitmessageAddress(privateKey);
|
||||||
|
assertEquals(address, identity.getAddress());
|
||||||
|
return identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BitmessageAddress loadContact() throws IOException {
|
||||||
|
BitmessageAddress address = new BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h");
|
||||||
|
ObjectMessage object = TestUtils.loadObjectMessage(4, "V4Pubkey.payload");
|
||||||
|
object.decrypt(address.getPubkeyDecryptionKey());
|
||||||
|
address.setPubkey((V4Pubkey) object.getPayload());
|
||||||
|
return address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -18,12 +18,16 @@ package ch.dissem.bitmessage.repository;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V3Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.V4Pubkey;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.AddressRepository;
|
import ch.dissem.bitmessage.ports.AddressRepository;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -62,7 +66,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getIdentities() {
|
public List<BitmessageAddress> getIdentities() {
|
||||||
return find("private_signing_key IS NOT NULL");
|
return find("private_key IS NOT NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,7 +76,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BitmessageAddress> getContacts() {
|
public List<BitmessageAddress> getContacts() {
|
||||||
return find("private_signing_key IS NULL");
|
return find("private_key IS NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<BitmessageAddress> find(String where) {
|
private List<BitmessageAddress> find(String where) {
|
||||||
@ -91,7 +95,10 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
|
|||||||
Blob publicKeyBlob = rs.getBlob("public_key");
|
Blob publicKeyBlob = rs.getBlob("public_key");
|
||||||
if (publicKeyBlob != null) {
|
if (publicKeyBlob != null) {
|
||||||
Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(),
|
Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(),
|
||||||
publicKeyBlob.getBinaryStream(), (int) publicKeyBlob.length());
|
publicKeyBlob.getBinaryStream(), (int) publicKeyBlob.length(), false);
|
||||||
|
if (address.getVersion() == 4) {
|
||||||
|
pubkey = new V4Pubkey((V3Pubkey) pubkey);
|
||||||
|
}
|
||||||
address.setPubkey(pubkey);
|
address.setPubkey(pubkey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +118,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
|
|||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address WHERE address='" + address.getAddress() + "'");
|
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM Address WHERE address='" + address.getAddress() + "'");
|
||||||
rs.next();
|
rs.next();
|
||||||
return rs.getInt(0) > 0;
|
return rs.getInt(1) > 0;
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
LOG.error(e.getMessage(), e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
@ -136,21 +143,32 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
|
|||||||
"UPDATE Address SET address=?, alias=?, public_key=?, private_key=?");
|
"UPDATE Address SET address=?, alias=?, public_key=?, private_key=?");
|
||||||
ps.setString(1, address.getAddress());
|
ps.setString(1, address.getAddress());
|
||||||
ps.setString(2, address.getAlias());
|
ps.setString(2, address.getAlias());
|
||||||
writeBlob(ps, 3, address.getPubkey());
|
writePubkey(ps, 3, address.getPubkey());
|
||||||
writeBlob(ps, 4, address.getPrivateKey());
|
writeBlob(ps, 4, address.getPrivateKey());
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insert(BitmessageAddress address) throws IOException, SQLException {
|
private void insert(BitmessageAddress address) throws IOException, SQLException {
|
||||||
PreparedStatement ps = getConnection().prepareStatement(
|
PreparedStatement ps = getConnection().prepareStatement(
|
||||||
"INSERT INTO Address (address, alias, public_key, private_key) VALUES (?, ?, ?, ?, ?)");
|
"INSERT INTO Address (address, alias, public_key, private_key) VALUES (?, ?, ?, ?)");
|
||||||
ps.setString(1, address.getAddress());
|
ps.setString(1, address.getAddress());
|
||||||
ps.setString(2, address.getAlias());
|
ps.setString(2, address.getAlias());
|
||||||
writeBlob(ps, 3, address.getPubkey());
|
writePubkey(ps, 3, address.getPubkey());
|
||||||
writeBlob(ps, 4, address.getPrivateKey());
|
writeBlob(ps, 4, address.getPrivateKey());
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void writePubkey(PreparedStatement ps, int parameterIndex, Pubkey data) throws SQLException, IOException {
|
||||||
|
if (data != null) {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
data.writeUnencrypted(out);
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
ps.setBlob(parameterIndex, in);
|
||||||
|
} else {
|
||||||
|
ps.setBlob(parameterIndex, (Blob) null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(BitmessageAddress address) {
|
public void remove(BitmessageAddress address) {
|
||||||
try {
|
try {
|
||||||
|
@ -24,10 +24,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.*;
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class that does Flyway migration, provides JDBC connections and some helper methods.
|
* Helper class that does Flyway migration, provides JDBC connections and some helper methods.
|
||||||
@ -47,10 +44,14 @@ abstract class JdbcHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeBlob(PreparedStatement ps, int parameterIndex, Streamable data) throws SQLException, IOException {
|
protected void writeBlob(PreparedStatement ps, int parameterIndex, Streamable data) throws SQLException, IOException {
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
if (data != null) {
|
||||||
data.write(os);
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
data.write(os);
|
||||||
ps.setBlob(parameterIndex, is);
|
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
||||||
|
ps.setBlob(parameterIndex, is);
|
||||||
|
} else {
|
||||||
|
ps.setBlob(parameterIndex, (Blob) null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Connection getConnection() {
|
protected Connection getConnection() {
|
||||||
|
@ -52,10 +52,23 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
private List<InventoryVector> getFullInventory(long... streams) {
|
||||||
|
List<InventoryVector> result = new LinkedList<>();
|
||||||
|
try {
|
||||||
|
Statement stmt = getConnection().createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery("SELECT hash FROM Inventory WHERE stream IN (" + join(streams) + ")");
|
||||||
|
while (rs.next()) {
|
||||||
|
result.add(new InventoryVector(rs.getBytes("hash")));
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<InventoryVector> getMissing(List<InventoryVector> offer, long... streams) {
|
public List<InventoryVector> getMissing(List<InventoryVector> offer, long... streams) {
|
||||||
offer.removeAll(getInventory(streams));
|
offer.removeAll(getFullInventory(streams));
|
||||||
return offer;
|
return offer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,17 +91,17 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ObjectMessage> getObjects(long stream, long version, ObjectType type) {
|
public List<ObjectMessage> getObjects(long stream, long version, ObjectType... types) {
|
||||||
try {
|
try {
|
||||||
StringBuilder query = new StringBuilder("SELECT data, version FROM Inventory WHERE 1=1");
|
StringBuilder query = new StringBuilder("SELECT data, version FROM Inventory WHERE 1=1");
|
||||||
if (stream >= 0) {
|
if (stream > 0) {
|
||||||
query.append(" AND stream = ").append(stream);
|
query.append(" AND stream = ").append(stream);
|
||||||
}
|
}
|
||||||
if (version >= 0) {
|
if (version > 0) {
|
||||||
query.append(" AND version = ").append(version);
|
query.append(" AND version = ").append(version);
|
||||||
}
|
}
|
||||||
if (type != null) {
|
if (types.length > 0) {
|
||||||
query.append(" AND type = ").append(type.getNumber());
|
query.append(" AND type IN (").append(join(types)).append(")");
|
||||||
}
|
}
|
||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery(query.toString());
|
ResultSet rs = stmt.executeQuery(query.toString());
|
||||||
|
@ -41,7 +41,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
List<String> result = new LinkedList<>();
|
List<String> result = new LinkedList<>();
|
||||||
try {
|
try {
|
||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT label FROM Label ORDER BY order");
|
ResultSet rs = stmt.executeQuery("SELECT label FROM Label ORDER BY ord");
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
result.add(rs.getString("label"));
|
result.add(rs.getString("label"));
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Plaintext> findMessages(Plaintext.Status status, BitmessageAddress recipient) {
|
public List<Plaintext> findMessages(Plaintext.Status status, BitmessageAddress recipient) {
|
||||||
return find("status='" + status.name() + "' AND to='" + recipient.getAddress() + "'");
|
return find("status='" + status.name() + "' AND recipient='" + recipient.getAddress() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,14 +70,14 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
List<Plaintext> result = new LinkedList<>();
|
List<Plaintext> result = new LinkedList<>();
|
||||||
try {
|
try {
|
||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT \"id\", \"from\", \"to\", \"data\", \"sent\", \"received\", \"status\" FROM Message WHERE " + where);
|
ResultSet rs = stmt.executeQuery("SELECT id, sender, recipient, data, sent, received, status FROM Message WHERE " + where);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Blob data = rs.getBlob("data");
|
Blob data = rs.getBlob("data");
|
||||||
Plaintext.Builder builder = Plaintext.readWithoutSignature(data.getBinaryStream());
|
Plaintext.Builder builder = Plaintext.readWithoutSignature(data.getBinaryStream());
|
||||||
long id = rs.getLong("id");
|
long id = rs.getLong("id");
|
||||||
builder.id(id);
|
builder.id(id);
|
||||||
builder.from(ctx.getAddressRepo().getAddress(rs.getString("from")));
|
builder.from(ctx.getAddressRepo().getAddress(rs.getString("sender")));
|
||||||
builder.to(ctx.getAddressRepo().getAddress(rs.getString("to")));
|
builder.to(ctx.getAddressRepo().getAddress(rs.getString("recipient")));
|
||||||
builder.sent(rs.getLong("sent"));
|
builder.sent(rs.getLong("sent"));
|
||||||
builder.received(rs.getLong("received"));
|
builder.received(rs.getLong("received"));
|
||||||
builder.status(Plaintext.Status.valueOf(rs.getString("status")));
|
builder.status(Plaintext.Status.valueOf(rs.getString("status")));
|
||||||
@ -94,7 +94,7 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
|
|||||||
List<Label> result = new ArrayList<>();
|
List<Label> result = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT \"label\", \"color\" FROM Label WHERE id IN SELECT label_id FROM Message_Label WHERE message_id=" + messageId);
|
ResultSet rs = stmt.executeQuery("SELECT label, color FROM Label WHERE id IN SELECT label_id FROM Message_Label WHERE message_id=" + messageId);
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
result.add(new Label(rs.getString("label"), rs.getInt("color")));
|
result.add(new Label(rs.getString("label"), rs.getInt("color")));
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ 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 (\"from\", \"to\", \"data\", \"sent\", \"received\", \"status\") VALUES (?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
|
"INSERT INTO Message (sender, recipient, data, sent, received, status) VALUES (?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setString(1, message.getFrom().getAddress());
|
ps.setString(1, message.getFrom().getAddress());
|
||||||
ps.setString(2, message.getTo().getAddress());
|
ps.setString(2, message.getTo().getAddress());
|
||||||
writeBlob(ps, 3, message);
|
writeBlob(ps, 3, message);
|
||||||
@ -168,7 +168,7 @@ 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\"=?");
|
"UPDATE Message SET sent=?, received=?, status=?");
|
||||||
ps.setLong(1, message.getSent());
|
ps.setLong(1, message.getSent());
|
||||||
ps.setLong(2, message.getReceived());
|
ps.setLong(2, message.getReceived());
|
||||||
ps.setString(3, message.getStatus().name());
|
ps.setString(3, message.getStatus().name());
|
||||||
|
@ -38,7 +38,7 @@ public class JdbcNodeRegistry extends JdbcHelper implements NodeRegistry {
|
|||||||
List<NetworkAddress> result = new LinkedList<>();
|
List<NetworkAddress> result = new LinkedList<>();
|
||||||
try {
|
try {
|
||||||
Statement stmt = getConnection().createStatement();
|
Statement stmt = getConnection().createStatement();
|
||||||
ResultSet rs = stmt.executeQuery("SELECT * FROM Node WHERE Stream IN (" + join(streams) + ")");
|
ResultSet rs = stmt.executeQuery("SELECT * FROM Node WHERE stream IN (" + join(streams) + ")");
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
// result.add(new NetworkAddress.Builder()
|
// result.add(new NetworkAddress.Builder()
|
||||||
// .ipv6(rs.getBytes("ip"))
|
// .ipv6(rs.getBytes("ip"))
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.repository;
|
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
|
||||||
import ch.dissem.bitmessage.entity.payload.ObjectType;
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
|
||||||
import ch.dissem.bitmessage.ports.Inventory;
|
|
||||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by chris on 06.04.15.
|
|
||||||
*/
|
|
||||||
public class SimpleInventory implements Inventory {
|
|
||||||
@Override
|
|
||||||
public List<InventoryVector> getInventory(long... streams) {
|
|
||||||
return new LinkedList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<InventoryVector> getMissing(List<InventoryVector> offer, long... streams) {
|
|
||||||
return offer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectMessage getObject(InventoryVector vector) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ObjectMessage> getObjects(long stream, long version, ObjectType type) {
|
|
||||||
return new LinkedList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void storeObject(ObjectMessage object) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanup() {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.repository;
|
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistry;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by chris on 06.04.15.
|
|
||||||
*/
|
|
||||||
public class SimpleNodeRegistry implements NodeRegistry {
|
|
||||||
@Override
|
|
||||||
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
|
||||||
return Collections.singletonList(new NetworkAddress.Builder().ipv4(127, 0, 0, 1).port(8444).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void offerAddresses(List<NetworkAddress> addresses) {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,9 @@
|
|||||||
CREATE TABLE Node (
|
CREATE TABLE Node (
|
||||||
"ip" BINARY(16) NOT NULL,
|
ip BINARY(16) NOT NULL,
|
||||||
"port" INT NOT NULL,
|
port INT NOT NULL,
|
||||||
"stream" BIGINT NOT NULL,
|
stream BIGINT NOT NULL,
|
||||||
"services" BIGINT NOT NULL,
|
services BIGINT NOT NULL,
|
||||||
"time" BIGINT NOT NULL,
|
time BIGINT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY ("ip", "port", "stream")
|
PRIMARY KEY (ip, port, stream)
|
||||||
);
|
);
|
@ -1,8 +1,8 @@
|
|||||||
CREATE TABLE Inventory (
|
CREATE TABLE Inventory (
|
||||||
"hash" BINARY(32) NOT NULL PRIMARY KEY,
|
hash BINARY(32) NOT NULL PRIMARY KEY,
|
||||||
"stream" BIGINT NOT NULL,
|
stream BIGINT NOT NULL,
|
||||||
"expires" BIGINT NOT NULL,
|
expires BIGINT NOT NULL,
|
||||||
"data" BLOB NOT NULL,
|
data BLOB NOT NULL,
|
||||||
"type" BIGINT NOT NULL,
|
type BIGINT NOT NULL,
|
||||||
"version" BIGINT NOT NULL
|
version BIGINT NOT NULL
|
||||||
);
|
);
|
@ -1,7 +1,7 @@
|
|||||||
CREATE TABLE Address (
|
CREATE TABLE Address (
|
||||||
"address" VARCHAR(40) NOT NULL PRIMARY KEY,
|
address VARCHAR(40) NOT NULL PRIMARY KEY,
|
||||||
"alias" VARCHAR(255),
|
alias VARCHAR(255),
|
||||||
"public_key" BLOB,
|
public_key BLOB,
|
||||||
"private_key" BLOB,
|
private_key BLOB,
|
||||||
"subscribed" BIT DEFAULT '0'
|
subscribed BIT DEFAULT '0'
|
||||||
);
|
);
|
@ -1,32 +1,35 @@
|
|||||||
CREATE TABLE Message (
|
CREATE TABLE Message (
|
||||||
"id" BIGINT AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
"from" VARCHAR(40) NOT NULL,
|
sender VARCHAR(40) NOT NULL,
|
||||||
"to" VARCHAR(40) NOT NULL,
|
recipient VARCHAR(40) NOT NULL,
|
||||||
"data" BLOB NOT NULL,
|
data BLOB NOT NULL,
|
||||||
"sent" BIGINT,
|
sent BIGINT,
|
||||||
"received" BIGINT,
|
received BIGINT,
|
||||||
"status" VARCHAR(20) NOT NULL
|
status VARCHAR(20) NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY (sender) REFERENCES Address (address),
|
||||||
|
FOREIGN KEY (recipient) REFERENCES Address (address)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Label (
|
CREATE TABLE Label (
|
||||||
"id" BIGINT AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
"label" VARCHAR(255) NOT NULL,
|
label VARCHAR(255) NOT NULL,
|
||||||
"color" INT,
|
color INT,
|
||||||
"order" BIGINT,
|
ord BIGINT,
|
||||||
CONSTRAINT UC_label UNIQUE ("label"),
|
CONSTRAINT UC_label UNIQUE (label),
|
||||||
CONSTRAINT UC_order UNIQUE ("order")
|
CONSTRAINT UC_order UNIQUE (ord)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Message_Label (
|
CREATE TABLE Message_Label (
|
||||||
"message_id" BIGINT NOT NULL,
|
message_id BIGINT NOT NULL,
|
||||||
"label_id" BIGINT NOT NULL,
|
label_id BIGINT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY ("message_id", "label_id"),
|
PRIMARY KEY (message_id, label_id),
|
||||||
FOREIGN KEY ("message_id") REFERENCES Message ("id"),
|
FOREIGN KEY (message_id) REFERENCES Message (id),
|
||||||
FOREIGN KEY ("label_id") REFERENCES Label ("id")
|
FOREIGN KEY (label_id) REFERENCES Label (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO Label("label", "order") VALUES ('Inbox', 0);
|
INSERT INTO Label(label, ord) VALUES ('Inbox', 0);
|
||||||
INSERT INTO Label("label", "order") VALUES ('Sent', 10);
|
INSERT INTO Label(label, ord) VALUES ('Sent', 10);
|
||||||
INSERT INTO Label("label", "order") VALUES ('Drafts', 20);
|
INSERT INTO Label(label, ord) VALUES ('Drafts', 20);
|
||||||
INSERT INTO Label("label", "order") VALUES ('Trash', 100);
|
INSERT INTO Label(label, ord) VALUES ('Trash', 100);
|
||||||
|
Loading…
Reference in New Issue
Block a user