Fixed a few problems:

- some bugs that creeped in when I moved security into its own adapter
- improved some DB code as it doesn't work in Android anyway
- all entities should be serializable (very useful in Android)
This commit is contained in:
Christian Basler 2015-08-28 13:48:01 +02:00
parent 4911c268c2
commit f89d1a342e
20 changed files with 83 additions and 38 deletions

View File

@ -22,8 +22,10 @@ dependencies {
compile project(':domain')
compile project(':networking')
compile project(':repositories')
compile project(':security-bc')
compile project(':wif')
compile 'org.slf4j:slf4j-simple:1.7.12'
compile 'args4j:args4j:2.32'
compile 'com.h2database:h2:1.4.187'
testCompile 'junit:junit:4.11'
}

View File

@ -21,7 +21,9 @@ import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
import ch.dissem.bitmessage.repository.*;
import ch.dissem.bitmessage.security.bc.BouncySecurity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,6 +48,7 @@ public class Application {
.nodeRegistry(new MemoryNodeRegistry())
.messageRepo(new JdbcMessageRepository(jdbcConfig))
.networkHandler(new DefaultNetworkHandler())
.security(new BouncySecurity())
.port(48444)
.build();

View File

@ -18,7 +18,9 @@ package ch.dissem.bitmessage.demo;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.networking.DefaultNetworkHandler;
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
import ch.dissem.bitmessage.repository.*;
import ch.dissem.bitmessage.security.bc.BouncySecurity;
import ch.dissem.bitmessage.wif.WifExporter;
import ch.dissem.bitmessage.wif.WifImporter;
import org.kohsuke.args4j.CmdLineException;
@ -50,6 +52,7 @@ public class Main {
.nodeRegistry(new MemoryNodeRegistry())
.messageRepo(new JdbcMessageRepository(jdbcConfig))
.networkHandler(new DefaultNetworkHandler())
.security(new BouncySecurity())
.port(48444)
.build();

View File

@ -81,7 +81,7 @@ public class InternalContext {
streams.add(1L);
}
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine);
init(inventory, nodeRegistry, networkHandler, addressRepository, messageRepository, proofOfWorkEngine, security);
}
private void init(Object... objects) {

View File

@ -19,9 +19,9 @@ package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.ports.Security;
import ch.dissem.bitmessage.utils.Decode;
import ch.dissem.bitmessage.utils.Encode;
import ch.dissem.bitmessage.utils.UnixTime;
import java.io.*;
import java.util.*;
@ -29,7 +29,7 @@ import java.util.*;
/**
* The unencrypted message to be sent by 'msg' or 'broadcast'.
*/
public class Plaintext implements Streamable, Serializable {
public class Plaintext implements Streamable {
private final Type type;
private final BitmessageAddress from;
private final long encoding;
@ -64,6 +64,7 @@ public class Plaintext implements Streamable, Serializable {
public static Plaintext read(Type type, InputStream in) throws IOException {
return readWithoutSignature(type, in)
.signature(Decode.varBytes(in))
.received(UnixTime.now())
.build();
}
@ -132,6 +133,15 @@ public class Plaintext implements Streamable, Serializable {
this.signature = signature;
}
public boolean isUnread() {
for (Label label : labels) {
if (label.getType() == Label.Type.UNREAD) {
return true;
}
}
return false;
}
public void write(OutputStream out, boolean includeSignature) throws IOException {
Encode.varInt(from.getVersion(), out);
Encode.varInt(from.getStream(), out);

View File

@ -16,14 +16,13 @@
package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.ports.Security;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
/**
* An object that can be written to an {@link OutputStream}
*/
public interface Streamable {
public interface Streamable extends Serializable {
void write(OutputStream stream) throws IOException;
}

View File

@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.Streamable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
/**
* The payload of an 'object' command. This is shared by the network.

View File

@ -16,9 +16,10 @@
package ch.dissem.bitmessage.entity.valueobject;
import java.io.Serializable;
import java.util.Objects;
public class Label {
public class Label implements Serializable {
private Object id;
private String label;
private Type type;

View File

@ -14,10 +14,9 @@
* limitations under the License.
*/
package ch.dissem.bitmessage.repository;
package ch.dissem.bitmessage.ports;
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
import ch.dissem.bitmessage.ports.NodeRegistry;
import ch.dissem.bitmessage.utils.UnixTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -21,6 +21,7 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
import ch.dissem.bitmessage.utils.Property;
import java.io.IOException;
import java.net.InetAddress;
/**
* Handles incoming messages
@ -30,6 +31,8 @@ public interface NetworkHandler {
void stop();
void synchronize(InetAddress trustedHost, int port, MessageListener listener) throws IOException;
void offer(InventoryVector iv);
Property getNetworkStatus();

View File

@ -16,12 +16,6 @@
package ch.dissem.bitmessage.utils;
import ch.dissem.bitmessage.entity.Streamable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* A helper class for working with byte arrays interpreted as unsigned big endian integers.
* This is one part due to the fact that Java doesn't support unsigned numbers, and another
@ -91,6 +85,8 @@ public class Bytes {
if (a < 0) return b < 0 && a < b;
if (b < 0) return a >= 0 || a < b;
return a < b;
// This would be easier to understand, but is (slightly) slower:
// return (a & 0xff) < (b & 0xff);
}
/**

View File

@ -117,6 +117,8 @@ public class Encode {
* @throws IOException if an I/O error occurs.
*/
public static byte[] bytes(Streamable streamable) throws IOException {
if (streamable == null) return null;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
streamable.write(stream);
return stream.toByteArray();

View File

@ -17,21 +17,21 @@
package ch.dissem.bitmessage.entity;
import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.factory.Factory;
import ch.dissem.bitmessage.utils.TestBase;
import ch.dissem.bitmessage.utils.TestUtils;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.util.Arrays;
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class SerializationTest {
public class SerializationTest extends TestBase {
@Test
public void ensureGetPubkeyIsDeserializedAndSerializedCorrectly() throws IOException {
doTest("V2GetPubkey.payload", 2, GetPubkey.class);
@ -75,7 +75,7 @@ public class SerializationTest {
}
@Test
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws IOException, DecryptionFailedException {
public void ensurePlaintextIsSerializedAndDeserializedCorrectly() throws Exception {
Plaintext p1 = new Plaintext.Builder(MSG)
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.to(TestUtils.loadContact())
@ -99,4 +99,21 @@ public class SerializationTest {
assertArrayEquals(data, out.toByteArray());
assertEquals(expectedPayloadType.getCanonicalName(), object.getPayload().getClass().getCanonicalName());
}
@Test
public void ensureSystemSerializationWorks() throws Exception {
Plaintext plaintext = new Plaintext.Builder(MSG)
.from(TestUtils.loadContact())
.to(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.labels(Arrays.asList(new Label("Test", Label.Type.INBOX, 0)))
.message("Test", "Test Test.\nTest")
.build();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(plaintext);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
assertEquals(plaintext, ois.readObject());
}
}

View File

@ -27,6 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
@ -149,6 +150,11 @@ public class DefaultNetworkHandler implements NetworkHandler, ContextHolder {
}
}
@Override
public void synchronize(InetAddress trustedHost, int port, MessageListener listener) throws IOException {
startConnection(new Connection(ctx, CLIENT, new Socket(trustedHost, port), listener, requestedObjects));
}
private void startConnection(Connection c) {
synchronized (connections) {
// prevent connecting twice to the same node

View File

@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Arrays;
import java.util.LinkedList;
@ -97,16 +98,16 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
while (rs.next()) {
BitmessageAddress address;
byte[] privateKeyBytes = rs.getBytes("private_key");
if (privateKeyBytes != null) {
PrivateKey privateKey = PrivateKey.read(new ByteArrayInputStream(privateKeyBytes));
InputStream privateKeyStream = rs.getBinaryStream("private_key");
if (privateKeyStream != null) {
PrivateKey privateKey = PrivateKey.read(privateKeyStream);
address = new BitmessageAddress(privateKey);
} else {
address = new BitmessageAddress(rs.getString("address"));
byte[] publicKeyBytes = rs.getBytes("public_key");
if (publicKeyBytes != null) {
Blob publicKeyBlob = rs.getBlob("public_key");
if (publicKeyBlob != null) {
Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(),
new ByteArrayInputStream(publicKeyBytes), publicKeyBytes.length, false);
publicKeyBlob.getBinaryStream(), (int) publicKeyBlob.length(), false);
if (address.getVersion() == 4 && pubkey instanceof V3Pubkey) {
pubkey = new V4Pubkey((V3Pubkey) pubkey);
}
@ -182,7 +183,7 @@ public class JdbcAddressRepository extends JdbcHelper implements AddressReposito
data.writeUnencrypted(out);
ps.setBytes(parameterIndex, out.toByteArray());
} else {
ps.setBlob(parameterIndex, (Blob) null);
ps.setBytes(parameterIndex, null);
}
}

View File

@ -21,10 +21,8 @@ import ch.dissem.bitmessage.entity.payload.ObjectType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.Blob;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@ -84,7 +82,7 @@ abstract class JdbcHelper {
data.write(os);
ps.setBytes(parameterIndex, os.toByteArray());
} else {
ps.setBlob(parameterIndex, (Blob) null);
ps.setBytes(parameterIndex, null);
}
}
}

View File

@ -53,6 +53,7 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
}
return result;
}
private List<InventoryVector> getFullInventory(long... streams) {
List<InventoryVector> result = new LinkedList<>();
try (Connection connection = config.getConnection()) {
@ -79,8 +80,8 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT data, version FROM Inventory WHERE hash = X'" + vector + "'");
if (rs.next()) {
byte[] data = rs.getBytes("data");
return Factory.getObjectMessage(rs.getInt("version"), new ByteArrayInputStream(data), data.length);
Blob data = rs.getBlob("data");
return Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length());
} else {
LOG.info("Object requested that we don't have. IV: " + vector);
return null;
@ -108,8 +109,8 @@ public class JdbcInventory extends JdbcHelper implements Inventory {
ResultSet rs = stmt.executeQuery(query.toString());
List<ObjectMessage> result = new LinkedList<>();
while (rs.next()) {
byte[] data = rs.getBytes("data");
result.add(Factory.getObjectMessage(rs.getInt("version"), new ByteArrayInputStream(data), data.length));
Blob data = rs.getBlob("data");
result.add(Factory.getObjectMessage(rs.getInt("version"), data.getBinaryStream(), (int) data.length()));
}
return result;
} catch (Exception e) {

View File

@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collection;
@ -107,9 +108,9 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
ResultSet rs = stmt.executeQuery("SELECT id, iv, type, sender, recipient, data, sent, received, status FROM Message WHERE " + where);
while (rs.next()) {
byte[] iv = rs.getBytes("iv");
byte[] data = rs.getBytes("data");
InputStream data = rs.getBinaryStream("data");
Plaintext.Type type = Plaintext.Type.valueOf(rs.getString("type"));
Plaintext.Builder builder = Plaintext.readWithoutSignature(type, new ByteArrayInputStream(data));
Plaintext.Builder builder = Plaintext.readWithoutSignature(type, data);
long id = rs.getLong("id");
builder.id(id);
builder.IV(new InventoryVector(iv));
@ -191,7 +192,8 @@ public class JdbcMessageRepository extends JdbcHelper implements MessageReposito
private void insert(Connection connection, Plaintext message) throws SQLException, IOException {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO Message (iv, type, 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.setBytes(1, message.getInventoryVector() != null ? message.getInventoryVector().getHash() : null);
ps.setString(2, message.getType().name());
ps.setString(3, message.getFrom().getAddress());

View File

@ -17,6 +17,7 @@
package ch.dissem.bitmessage.repository;
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
import ch.dissem.bitmessage.ports.MemoryNodeRegistry;
import ch.dissem.bitmessage.ports.NodeRegistry;
import org.junit.Before;
import org.junit.Test;