diff --git a/build.gradle b/build.gradle
index 78bf578..2169e2f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,22 +1,38 @@
+buildscript {
+ ext.kotlin_version = '1.1.3'
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
plugins {
- id 'com.github.ben-manes.versions' version '0.14.0'
+ id 'com.github.ben-manes.versions' version '0.15.0'
+ id "io.spring.dependency-management" version "1.0.3.RELEASE"
}
subprojects {
- apply plugin: 'java'
+ apply plugin: 'kotlin'
apply plugin: 'maven'
apply plugin: 'signing'
apply plugin: 'jacoco'
apply plugin: 'gitflow-version'
+ apply plugin: 'io.spring.dependency-management'
apply plugin: 'com.github.ben-manes.versions'
sourceCompatibility = 1.7
+ targetCompatibility = 1.7
group = 'ch.dissem.jabit'
repositories {
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
+ dependencies {
+ compile "org.jetbrains.kotlin:kotlin-stdlib-jre7"
+ compile "org.jetbrains.kotlin:kotlin-reflect"
+ }
test {
testLogging {
@@ -38,6 +54,14 @@ subprojects {
archives javadocJar, sourcesJar
}
+ jar {
+ manifest {
+ attributes 'Implementation-Title': "Jabit ${project.name.capitalize()}",
+ 'Implementation-Version': version
+ }
+ baseName "jabit-${project.name}"
+ }
+
signing {
required { isRelease && project.getProperties().get("signing.keyId")?.length() > 0 }
sign configurations.archives
@@ -93,4 +117,31 @@ subprojects {
}
check.dependsOn jacocoTestReport
+
+ dependencyManagement {
+ dependencies {
+ dependencySet(group: 'org.jetbrains.kotlin', version: "$kotlin_version") {
+ entry 'kotlin-stdlib-jre7'
+ entry 'kotlin-reflect'
+ }
+ dependencySet(group: 'org.slf4j', version: '1.7.25') {
+ entry 'slf4j-api'
+ entry 'slf4j-simple'
+ }
+
+ dependency 'ch.dissem.msgpack:msgpack:1.0.0'
+ dependency 'org.bouncycastle:bcprov-jdk15on:1.57'
+ dependency 'com.madgag.spongycastle:prov:1.56.0.0'
+ dependency 'org.apache.commons:commons-lang3:3.6'
+ dependency 'org.flywaydb:flyway-core:4.2.0'
+
+ dependency 'args4j:args4j:2.33'
+ dependency 'org.ini4j:ini4j:0.5.4'
+ dependency 'com.h2database:h2:1.4.196'
+
+ dependency 'junit:junit:4.12'
+ dependency 'org.hamcrest:hamcrest-library:1.3'
+ dependency 'com.nhaarman:mockito-kotlin:1.5.0'
+ }
+ }
}
diff --git a/core/build.gradle b/core/build.gradle
index 785507e..6af7a84 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -24,10 +24,28 @@ artifacts {
}
dependencies {
- compile 'org.slf4j:slf4j-api:1.7.25'
+ compile 'org.slf4j:slf4j-api'
compile 'ch.dissem.msgpack:msgpack:1.0.0'
testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-library:1.3'
- testCompile 'org.mockito:mockito-core:2.7.21'
+ testCompile 'com.nhaarman:mockito-kotlin:1.5.0'
testCompile project(':cryptography-bc')
}
+
+def generatedResources = "${project.buildDir}/generated-resources/main"
+
+sourceSets {
+ main {
+ output.dir(generatedResources, builtBy: 'generateVersionInfo')
+ }
+}
+task('generateVersionInfo') {
+ doLast {
+ def dir = new File(generatedResources)
+ if (!dir.exists()) {
+ dir.mkdirs()
+ }
+ def file = new File(generatedResources, "version")
+ file.write(project.version.toString())
+ }
+}
diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java
deleted file mode 100644
index 29639e7..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.java
+++ /dev/null
@@ -1,437 +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;
-
-import ch.dissem.bitmessage.entity.*;
-import ch.dissem.bitmessage.entity.payload.Broadcast;
-import ch.dissem.bitmessage.entity.payload.ObjectType;
-import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
-import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
-import ch.dissem.bitmessage.exception.DecryptionFailedException;
-import ch.dissem.bitmessage.factory.Factory;
-import ch.dissem.bitmessage.ports.*;
-import ch.dissem.bitmessage.utils.Property;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetAddress;
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-import static ch.dissem.bitmessage.InternalContext.NETWORK_EXTRA_BYTES;
-import static ch.dissem.bitmessage.InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE;
-import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST;
-import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
-import static ch.dissem.bitmessage.utils.UnixTime.HOUR;
-import static ch.dissem.bitmessage.utils.UnixTime.MINUTE;
-
-/**
- *
Use this class if you want to create a Bitmessage client.
- * You'll need the Builder to create a BitmessageContext, and set the following properties:
- *
- * - addressRepo
- * - inventory
- * - nodeRegistry
- * - networkHandler
- * - messageRepo
- * - streams
- *
- * The default implementations in the different module builds can be used.
- * The port defaults to 8444 (the default Bitmessage port)
- */
-public class BitmessageContext {
- public static final int CURRENT_VERSION = 3;
- private final static Logger LOG = LoggerFactory.getLogger(BitmessageContext.class);
-
- private final InternalContext ctx;
-
- private final Labeler labeler;
-
- private final boolean sendPubkeyOnIdentityCreation;
-
- private BitmessageContext(Builder builder) {
- ctx = new InternalContext(builder);
- labeler = builder.labeler;
- ctx.getProofOfWorkService().doMissingProofOfWork(30_000); // TODO: this should be configurable
- sendPubkeyOnIdentityCreation = builder.sendPubkeyOnIdentityCreation;
- if (builder.listener instanceof Listener.WithContext) {
- ((Listener.WithContext) builder.listener).setContext(this);
- }
- }
-
- public AddressRepository addresses() {
- return ctx.getAddressRepository();
- }
-
- public MessageRepository messages() {
- return ctx.getMessageRepository();
- }
-
- public Labeler labeler() {
- return labeler;
- }
-
- public BitmessageAddress createIdentity(boolean shorter, Feature... features) {
- final BitmessageAddress identity = new BitmessageAddress(new PrivateKey(
- shorter,
- ctx.getStreams()[0],
- NETWORK_NONCE_TRIALS_PER_BYTE,
- NETWORK_EXTRA_BYTES,
- features
- ));
- ctx.getAddressRepository().save(identity);
- if (sendPubkeyOnIdentityCreation) {
- ctx.sendPubkey(identity, identity.getStream());
- }
- return identity;
- }
-
- public BitmessageAddress joinChan(String passphrase, String address) {
- BitmessageAddress chan = BitmessageAddress.chan(address, passphrase);
- chan.setAlias(passphrase);
- ctx.getAddressRepository().save(chan);
- return chan;
- }
-
- public BitmessageAddress createChan(String passphrase) {
- // FIXME: hardcoded stream number
- BitmessageAddress chan = BitmessageAddress.chan(1, passphrase);
- ctx.getAddressRepository().save(chan);
- return chan;
- }
-
- public List createDeterministicAddresses(
- String passphrase, int numberOfAddresses, long version, long stream, boolean shorter) {
- List result = BitmessageAddress.deterministic(
- passphrase, numberOfAddresses, version, stream, shorter);
- for (int i = 0; i < result.size(); i++) {
- BitmessageAddress address = result.get(i);
- address.setAlias("deterministic (" + (i + 1) + ")");
- ctx.getAddressRepository().save(address);
- }
- return result;
- }
-
- public void broadcast(final BitmessageAddress from, final String subject, final String message) {
- Plaintext msg = new Plaintext.Builder(BROADCAST)
- .from(from)
- .message(subject, message)
- .build();
- send(msg);
- }
-
- public void send(final BitmessageAddress from, final BitmessageAddress to, final String subject, final String message) {
- if (from.getPrivateKey() == null) {
- throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key.");
- }
- Plaintext msg = new Plaintext.Builder(MSG)
- .from(from)
- .to(to)
- .message(subject, message)
- .build();
- send(msg);
- }
-
- public void send(final Plaintext msg) {
- if (msg.getFrom() == null || msg.getFrom().getPrivateKey() == null) {
- throw new IllegalArgumentException("'From' must be an identity, i.e. have a private key.");
- }
- labeler().markAsSending(msg);
- BitmessageAddress to = msg.getTo();
- if (to != null) {
- if (to.getPubkey() == null) {
- LOG.info("Public key is missing from recipient. Requesting.");
- ctx.requestPubkey(to);
- }
- if (to.getPubkey() == null) {
- ctx.getMessageRepository().save(msg);
- }
- }
- if (to == null || to.getPubkey() != null) {
- LOG.info("Sending message.");
- ctx.getMessageRepository().save(msg);
- if (msg.getType() == MSG) {
- ctx.send(msg);
- } else {
- ctx.send(
- msg.getFrom(),
- to,
- Factory.getBroadcast(msg),
- msg.getTTL()
- );
- }
- }
- }
-
- public void startup() {
- ctx.getNetworkHandler().start();
- }
-
- public void shutdown() {
- ctx.getNetworkHandler().stop();
- }
-
- /**
- * @param host a trusted node that must be reliable (it's used for every synchronization)
- * @param port of the trusted host, default is 8444
- * @param timeoutInSeconds synchronization should end no later than about 5 seconds after the timeout elapsed, even
- * if not all objects were fetched
- * @param wait waits for the synchronization thread to finish
- */
- public void synchronize(InetAddress host, int port, long timeoutInSeconds, boolean wait) {
- Future> future = ctx.getNetworkHandler().synchronize(host, port, timeoutInSeconds);
- if (wait) {
- try {
- future.get();
- } catch (InterruptedException e) {
- LOG.info("Thread was interrupted. Trying to shut down synchronization and returning.");
- future.cancel(true);
- } catch (CancellationException | ExecutionException e) {
- LOG.debug(e.getMessage(), e);
- }
- }
- }
-
- /**
- * Send a custom message to a specific node (that should implement handling for this message type) and returns
- * the response, which in turn is expected to be a {@link CustomMessage}.
- *
- * @param server the node's address
- * @param port the node's port
- * @param request the request
- * @return the response
- */
- public CustomMessage send(InetAddress server, int port, CustomMessage request) {
- return ctx.getNetworkHandler().send(server, port, request);
- }
-
- /**
- * Removes expired objects from the inventory. You should call this method regularly,
- * e.g. daily and on each shutdown.
- */
- public void cleanup() {
- ctx.getInventory().cleanup();
- }
-
- /**
- * Sends messages again whose time to live expired without being acknowledged. (And whose
- * recipient is expected to send acknowledgements.
- *
- * You should call this method regularly, but be aware of the following:
- *
- * - As messages might be sent, POW will be done. It is therefore not advised to
- * call it on shutdown.
- * - It shouldn't be called right after startup, as it's possible the missing
- * acknowledgement was sent while the client was offline.
- * - Other than that, the call isn't expensive as long as there is no message
- * to send, so it might be a good idea to just call it every few minutes.
- *
- */
- public void resendUnacknowledgedMessages() {
- ctx.resendUnacknowledged();
- }
-
- public boolean isRunning() {
- return ctx.getNetworkHandler().isRunning();
- }
-
- public void addContact(BitmessageAddress contact) {
- ctx.getAddressRepository().save(contact);
- if (contact.getPubkey() == null) {
- BitmessageAddress stored = ctx.getAddressRepository().getAddress(contact.getAddress());
- if (stored.getPubkey() == null) {
- ctx.requestPubkey(contact);
- }
- }
- }
-
- public void addSubscribtion(BitmessageAddress address) {
- address.setSubscribed(true);
- ctx.getAddressRepository().save(address);
- tryToFindBroadcastsForAddress(address);
- }
-
- private void tryToFindBroadcastsForAddress(BitmessageAddress address) {
- for (ObjectMessage object : ctx.getInventory().getObjects(address.getStream(), Broadcast.getVersion(address), ObjectType.BROADCAST)) {
- try {
- Broadcast broadcast = (Broadcast) object.getPayload();
- broadcast.decrypt(address);
- // This decrypts it twice, but on the other hand it doesn't try to decrypt the objects with
- // other subscriptions and the interface stays as simple as possible.
- ctx.getNetworkListener().receive(object);
- } catch (DecryptionFailedException ignore) {
- } catch (Exception e) {
- LOG.debug(e.getMessage(), e);
- }
- }
- }
-
- public Property status() {
- return new Property("status", null,
- ctx.getNetworkHandler().getNetworkStatus(),
- new Property("unacknowledged", ctx.getMessageRepository().findMessagesToResend().size())
- );
- }
-
- /**
- * Returns the {@link InternalContext} - normally you wouldn't need it,
- * unless you are doing something crazy with the protocol.
- */
- public InternalContext internals() {
- return ctx;
- }
-
- public interface Listener {
- void receive(Plaintext plaintext);
-
- /**
- * A message listener that needs a {@link BitmessageContext}, i.e. for implementing some sort of chat bot.
- */
- interface WithContext extends Listener {
- void setContext(BitmessageContext ctx);
- }
- }
-
- public static final class Builder {
- int port = 8444;
- Inventory inventory;
- NodeRegistry nodeRegistry;
- NetworkHandler networkHandler;
- AddressRepository addressRepo;
- MessageRepository messageRepo;
- ProofOfWorkRepository proofOfWorkRepository;
- ProofOfWorkEngine proofOfWorkEngine;
- Cryptography cryptography;
- CustomCommandHandler customCommandHandler;
- Labeler labeler;
- Listener listener;
- int connectionLimit = 150;
- long connectionTTL = 30 * MINUTE;
- boolean sendPubkeyOnIdentityCreation = true;
-
- public Builder port(int port) {
- this.port = port;
- return this;
- }
-
- public Builder inventory(Inventory inventory) {
- this.inventory = inventory;
- return this;
- }
-
- public Builder nodeRegistry(NodeRegistry nodeRegistry) {
- this.nodeRegistry = nodeRegistry;
- return this;
- }
-
- public Builder networkHandler(NetworkHandler networkHandler) {
- this.networkHandler = networkHandler;
- return this;
- }
-
- public Builder addressRepo(AddressRepository addressRepo) {
- this.addressRepo = addressRepo;
- return this;
- }
-
- public Builder messageRepo(MessageRepository messageRepo) {
- this.messageRepo = messageRepo;
- return this;
- }
-
- public Builder powRepo(ProofOfWorkRepository proofOfWorkRepository) {
- this.proofOfWorkRepository = proofOfWorkRepository;
- return this;
- }
-
- public Builder cryptography(Cryptography cryptography) {
- this.cryptography = cryptography;
- return this;
- }
-
- public Builder customCommandHandler(CustomCommandHandler handler) {
- this.customCommandHandler = handler;
- return this;
- }
-
- public Builder proofOfWorkEngine(ProofOfWorkEngine proofOfWorkEngine) {
- this.proofOfWorkEngine = proofOfWorkEngine;
- return this;
- }
-
- public Builder labeler(Labeler labeler) {
- this.labeler = labeler;
- return this;
- }
-
- public Builder listener(Listener listener) {
- this.listener = listener;
- return this;
- }
-
- public Builder connectionLimit(int connectionLimit) {
- this.connectionLimit = connectionLimit;
- return this;
- }
-
- public Builder connectionTTL(int hours) {
- this.connectionTTL = hours * HOUR;
- return this;
- }
-
- /**
- * By default a client will send the public key when an identity is being created. On weaker devices
- * this behaviour might not be desirable.
- */
- public Builder doNotSendPubkeyOnIdentityCreation() {
- this.sendPubkeyOnIdentityCreation = false;
- return this;
- }
-
- public BitmessageContext build() {
- nonNull("inventory", inventory);
- nonNull("nodeRegistry", nodeRegistry);
- nonNull("networkHandler", networkHandler);
- nonNull("addressRepo", addressRepo);
- nonNull("messageRepo", messageRepo);
- nonNull("proofOfWorkRepo", proofOfWorkRepository);
- if (proofOfWorkEngine == null) {
- proofOfWorkEngine = new MultiThreadedPOWEngine();
- }
- if (labeler == null) {
- labeler = new DefaultLabeler();
- }
- if (customCommandHandler == null) {
- customCommandHandler = new CustomCommandHandler() {
- @Override
- public MessagePayload handle(CustomMessage request) {
- LOG.debug("Received custom request, but no custom command handler configured.");
- return null;
- }
- };
- }
- return new BitmessageContext(this);
- }
-
- private void nonNull(String name, Object o) {
- if (o == null) throw new IllegalStateException(name + " must not be null");
- }
- }
-
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java
deleted file mode 100644
index 4fb438f..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.java
+++ /dev/null
@@ -1,191 +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;
-
-import ch.dissem.bitmessage.entity.BitmessageAddress;
-import ch.dissem.bitmessage.entity.ObjectMessage;
-import ch.dissem.bitmessage.entity.Plaintext;
-import ch.dissem.bitmessage.entity.payload.*;
-import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
-import ch.dissem.bitmessage.exception.DecryptionFailedException;
-import ch.dissem.bitmessage.ports.Labeler;
-import ch.dissem.bitmessage.ports.NetworkHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-import static ch.dissem.bitmessage.entity.Plaintext.Status.PUBKEY_REQUESTED;
-
-class DefaultMessageListener implements NetworkHandler.MessageListener, InternalContext.ContextHolder {
- private final static Logger LOG = LoggerFactory.getLogger(DefaultMessageListener.class);
- private final Labeler labeler;
- private final BitmessageContext.Listener listener;
- private InternalContext ctx;
-
- public DefaultMessageListener(Labeler labeler, BitmessageContext.Listener listener) {
- this.labeler = labeler;
- this.listener = listener;
- }
-
- @Override
- public void setContext(InternalContext context) {
- this.ctx = context;
- }
-
- @Override
- @SuppressWarnings("ConstantConditions")
- public void receive(ObjectMessage object) throws IOException {
- ObjectPayload payload = object.getPayload();
- if (payload.getType() == null) {
- if (payload instanceof GenericPayload) {
- receive((GenericPayload) payload);
- }
- return;
- }
-
- switch (payload.getType()) {
- case GET_PUBKEY: {
- receive(object, (GetPubkey) payload);
- break;
- }
- case PUBKEY: {
- receive(object, (Pubkey) payload);
- break;
- }
- case MSG: {
- receive(object, (Msg) payload);
- break;
- }
- case BROADCAST: {
- receive(object, (Broadcast) payload);
- break;
- }
- default: {
- throw new IllegalArgumentException("Unknown payload type " + payload.getType());
- }
- }
- }
-
- protected void receive(ObjectMessage object, GetPubkey getPubkey) {
- BitmessageAddress identity = ctx.getAddressRepository().findIdentity(getPubkey.getRipeTag());
- if (identity != null && identity.getPrivateKey() != null && !identity.isChan()) {
- LOG.info("Got pubkey request for identity " + identity);
- // FIXME: only send pubkey if it wasn't sent in the last TTL.pubkey() days
- ctx.sendPubkey(identity, object.getStream());
- }
- }
-
- protected void receive(ObjectMessage object, Pubkey pubkey) throws IOException {
- BitmessageAddress address;
- try {
- if (pubkey instanceof V4Pubkey) {
- V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
- address = ctx.getAddressRepository().findContact(v4Pubkey.getTag());
- if (address != null) {
- v4Pubkey.decrypt(address.getPublicDecryptionKey());
- }
- } else {
- address = ctx.getAddressRepository().findContact(pubkey.getRipe());
- }
- if (address != null && address.getPubkey() == null) {
- updatePubkey(address, pubkey);
- }
- } catch (DecryptionFailedException ignore) {
- }
- }
-
- private void updatePubkey(BitmessageAddress address, Pubkey pubkey) {
- address.setPubkey(pubkey);
- LOG.info("Got pubkey for contact " + address);
- ctx.getAddressRepository().save(address);
- List messages = ctx.getMessageRepository().findMessages(PUBKEY_REQUESTED, address);
- LOG.info("Sending " + messages.size() + " messages for contact " + address);
- for (Plaintext msg : messages) {
- ctx.getLabeler().markAsSending(msg);
- ctx.getMessageRepository().save(msg);
- ctx.send(msg);
- }
- }
-
- protected void receive(ObjectMessage object, Msg msg) throws IOException {
- for (BitmessageAddress identity : ctx.getAddressRepository().getIdentities()) {
- try {
- msg.decrypt(identity.getPrivateKey().getPrivateEncryptionKey());
- Plaintext plaintext = msg.getPlaintext();
- plaintext.setTo(identity);
- if (!object.isSignatureValid(plaintext.getFrom().getPubkey())) {
- LOG.warn("Msg with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
- } else {
- receive(object.getInventoryVector(), plaintext);
- }
- break;
- } catch (DecryptionFailedException ignore) {
- }
- }
- }
-
- protected void receive(GenericPayload ack) {
- if (ack.getData().length == Msg.ACK_LENGTH) {
- Plaintext msg = ctx.getMessageRepository().getMessageForAck(ack.getData());
- if (msg != null) {
- ctx.getLabeler().markAsAcknowledged(msg);
- ctx.getMessageRepository().save(msg);
- }
- }
- }
-
- protected void receive(ObjectMessage object, Broadcast broadcast) throws IOException {
- byte[] tag = broadcast instanceof V5Broadcast ? ((V5Broadcast) broadcast).getTag() : null;
- for (BitmessageAddress subscription : ctx.getAddressRepository().getSubscriptions(broadcast.getVersion())) {
- if (tag != null && !Arrays.equals(tag, subscription.getTag())) {
- continue;
- }
- try {
- broadcast.decrypt(subscription.getPublicDecryptionKey());
- if (!object.isSignatureValid(broadcast.getPlaintext().getFrom().getPubkey())) {
- LOG.warn("Broadcast with IV " + object.getInventoryVector() + " was successfully decrypted, but signature check failed. Ignoring.");
- } else {
- receive(object.getInventoryVector(), broadcast.getPlaintext());
- }
- } catch (DecryptionFailedException ignore) {
- }
- }
- }
-
- protected void receive(InventoryVector iv, Plaintext msg) {
- BitmessageAddress contact = ctx.getAddressRepository().getAddress(msg.getFrom().getAddress());
- if (contact != null && contact.getPubkey() == null) {
- updatePubkey(contact, msg.getFrom().getPubkey());
- }
-
- msg.setInventoryVector(iv);
- labeler.setLabels(msg);
- ctx.getMessageRepository().save(msg);
- listener.receive(msg);
-
- if (msg.getType() == Plaintext.Type.MSG && msg.getTo().has(Pubkey.Feature.DOES_ACK)) {
- ObjectMessage ack = msg.getAckMessage();
- if (ack != null) {
- ctx.getInventory().storeObject(ack);
- ctx.getNetworkHandler().offer(ack.getInventoryVector());
- }
- }
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java b/core/src/main/java/ch/dissem/bitmessage/InternalContext.java
deleted file mode 100644
index 007e8f2..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.java
+++ /dev/null
@@ -1,326 +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;
-
-import ch.dissem.bitmessage.entity.*;
-import ch.dissem.bitmessage.entity.payload.*;
-import ch.dissem.bitmessage.exception.ApplicationException;
-import ch.dissem.bitmessage.ports.*;
-import ch.dissem.bitmessage.utils.Singleton;
-import ch.dissem.bitmessage.utils.TTL;
-import ch.dissem.bitmessage.utils.UnixTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.TreeSet;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-/**
- * 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
- * get extended.
- *
- * On the other hand, if you need the BitmessageContext in a port implementation, the same thing might apply.
- *
- */
-public class InternalContext {
- private final static Logger LOG = LoggerFactory.getLogger(InternalContext.class);
-
- public final static long NETWORK_NONCE_TRIALS_PER_BYTE = 1000;
- public final static long NETWORK_EXTRA_BYTES = 1000;
-
- private final Executor threadPool = Executors.newCachedThreadPool();
-
- private final Cryptography cryptography;
- private final Inventory inventory;
- private final NodeRegistry nodeRegistry;
- private final NetworkHandler networkHandler;
- private final AddressRepository addressRepository;
- private final MessageRepository messageRepository;
- private final ProofOfWorkRepository proofOfWorkRepository;
- private final ProofOfWorkEngine proofOfWorkEngine;
- private final CustomCommandHandler customCommandHandler;
- private final ProofOfWorkService proofOfWorkService;
- private final Labeler labeler;
- private final NetworkHandler.MessageListener networkListener;
-
- private final TreeSet streams = new TreeSet<>();
- private final int port;
- private final long clientNonce;
- private long connectionTTL;
- private int connectionLimit;
-
- public InternalContext(BitmessageContext.Builder builder) {
- this.cryptography = builder.cryptography;
- this.inventory = builder.inventory;
- this.nodeRegistry = builder.nodeRegistry;
- this.networkHandler = builder.networkHandler;
- this.addressRepository = builder.addressRepo;
- this.messageRepository = builder.messageRepo;
- this.proofOfWorkRepository = builder.proofOfWorkRepository;
- this.proofOfWorkService = new ProofOfWorkService();
- this.proofOfWorkEngine = builder.proofOfWorkEngine;
- this.clientNonce = cryptography.randomNonce();
- this.customCommandHandler = builder.customCommandHandler;
- this.port = builder.port;
- this.connectionLimit = builder.connectionLimit;
- this.connectionTTL = builder.connectionTTL;
- this.labeler = builder.labeler;
- this.networkListener = new DefaultMessageListener(labeler, builder.listener);
-
- Singleton.initialize(cryptography);
-
- // TODO: streams of new identities and subscriptions should also be added. This works only after a restart.
- for (BitmessageAddress address : addressRepository.getIdentities()) {
- streams.add(address.getStream());
- }
- for (BitmessageAddress address : addressRepository.getSubscriptions()) {
- streams.add(address.getStream());
- }
- if (streams.isEmpty()) {
- streams.add(1L);
- }
-
- init(cryptography, inventory, nodeRegistry, networkHandler, addressRepository, messageRepository,
- proofOfWorkRepository, proofOfWorkService, proofOfWorkEngine, customCommandHandler, builder.labeler,
- networkListener);
- for (BitmessageAddress identity : addressRepository.getIdentities()) {
- streams.add(identity.getStream());
- }
- }
-
- private void init(Object... objects) {
- for (Object o : objects) {
- if (o instanceof ContextHolder) {
- ((ContextHolder) o).setContext(this);
- }
- }
- }
-
- public Cryptography getCryptography() {
- return cryptography;
- }
-
- public Inventory getInventory() {
- return inventory;
- }
-
- public NodeRegistry getNodeRegistry() {
- return nodeRegistry;
- }
-
- public NetworkHandler getNetworkHandler() {
- return networkHandler;
- }
-
- public AddressRepository getAddressRepository() {
- return addressRepository;
- }
-
- public MessageRepository getMessageRepository() {
- return messageRepository;
- }
-
- public ProofOfWorkRepository getProofOfWorkRepository() {
- return proofOfWorkRepository;
- }
-
- public ProofOfWorkEngine getProofOfWorkEngine() {
- return proofOfWorkEngine;
- }
-
- public ProofOfWorkService getProofOfWorkService() {
- return proofOfWorkService;
- }
-
- public Labeler getLabeler() {
- return labeler;
- }
-
- public NetworkHandler.MessageListener getNetworkListener() {
- return networkListener;
- }
-
- public long[] getStreams() {
- long[] result = new long[streams.size()];
- int i = 0;
- for (long stream : streams) {
- result[i++] = stream;
- }
- return result;
- }
-
- public int getPort() {
- return port;
- }
-
- public void send(final Plaintext plaintext) {
- if (plaintext.getAckMessage() != null) {
- long expires = UnixTime.now(+plaintext.getTTL());
- LOG.info("Expires at " + expires);
- proofOfWorkService.doProofOfWorkWithAck(plaintext, expires);
- } else {
- send(plaintext.getFrom(), plaintext.getTo(), new Msg(plaintext), plaintext.getTTL());
- }
- }
-
- public void send(final BitmessageAddress from, BitmessageAddress to, final ObjectPayload payload,
- final long timeToLive) {
- try {
- final BitmessageAddress recipient = (to != null ? to : from);
- long expires = UnixTime.now(+timeToLive);
- LOG.info("Expires at " + expires);
- final ObjectMessage object = new ObjectMessage.Builder()
- .stream(recipient.getStream())
- .expiresTime(expires)
- .payload(payload)
- .build();
- if (object.isSigned()) {
- object.sign(from.getPrivateKey());
- }
- if (payload instanceof Broadcast) {
- ((Broadcast) payload).encrypt();
- } else if (payload instanceof Encrypted) {
- object.encrypt(recipient.getPubkey());
- }
- proofOfWorkService.doProofOfWork(to, object);
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public void sendPubkey(final BitmessageAddress identity, final long targetStream) {
- try {
- long expires = UnixTime.now(TTL.pubkey());
- LOG.info("Expires at " + expires);
- final ObjectMessage response = new ObjectMessage.Builder()
- .stream(targetStream)
- .expiresTime(expires)
- .payload(identity.getPubkey())
- .build();
- response.sign(identity.getPrivateKey());
- response.encrypt(cryptography.createPublicKey(identity.getPublicDecryptionKey()));
- // TODO: remember that the pubkey is just about to be sent, and on which stream!
- proofOfWorkService.doProofOfWork(response);
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- /**
- * Be aware that if the pubkey already exists in the inventory, the metods will not request it and the callback
- * for freshly received pubkeys will not be called. Instead the pubkey is added to the contact and stored on DB.
- */
- public void requestPubkey(final BitmessageAddress contact) {
- threadPool.execute(new Runnable() {
- @Override
- public void run() {
- BitmessageAddress stored = addressRepository.getAddress(contact.getAddress());
-
- tryToFindMatchingPubkey(contact);
- if (contact.getPubkey() != null) {
- if (stored != null) {
- stored.setPubkey(contact.getPubkey());
- addressRepository.save(stored);
- } else {
- addressRepository.save(contact);
- }
- return;
- }
-
- if (stored == null) {
- addressRepository.save(contact);
- }
-
- long expires = UnixTime.now(TTL.getpubkey());
- LOG.info("Expires at " + expires);
- final ObjectMessage request = new ObjectMessage.Builder()
- .stream(contact.getStream())
- .expiresTime(expires)
- .payload(new GetPubkey(contact))
- .build();
- proofOfWorkService.doProofOfWork(request);
- }
- });
- }
-
- private void tryToFindMatchingPubkey(BitmessageAddress address) {
- BitmessageAddress stored = addressRepository.getAddress(address.getAddress());
- if (stored != null) {
- address.setAlias(stored.getAlias());
- address.setSubscribed(stored.isSubscribed());
- }
- for (ObjectMessage object : inventory.getObjects(address.getStream(), address.getVersion(), ObjectType.PUBKEY)) {
- try {
- Pubkey pubkey = (Pubkey) object.getPayload();
- if (address.getVersion() == 4) {
- V4Pubkey v4Pubkey = (V4Pubkey) pubkey;
- if (Arrays.equals(address.getTag(), v4Pubkey.getTag())) {
- v4Pubkey.decrypt(address.getPublicDecryptionKey());
- if (object.isSignatureValid(v4Pubkey)) {
- address.setPubkey(v4Pubkey);
- addressRepository.save(address);
- break;
- } else {
- LOG.info("Found pubkey for " + address + " but signature is invalid");
- }
- }
- } else {
- if (Arrays.equals(pubkey.getRipe(), address.getRipe())) {
- address.setPubkey(pubkey);
- addressRepository.save(address);
- break;
- }
- }
- } catch (Exception e) {
- LOG.debug(e.getMessage(), e);
- }
- }
- }
-
- public void resendUnacknowledged() {
- List messages = messageRepository.findMessagesToResend();
- for (Plaintext message : messages) {
- send(message);
- messageRepository.save(message);
- }
- }
-
- public long getClientNonce() {
- return clientNonce;
- }
-
- public long getConnectionTTL() {
- return connectionTTL;
- }
-
- public int getConnectionLimit() {
- return connectionLimit;
- }
-
- public CustomCommandHandler getCustomCommandHandler() {
- return customCommandHandler;
- }
-
- public interface ContextHolder {
- void setContext(InternalContext context);
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java
deleted file mode 100644
index 14e7c8a..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package ch.dissem.bitmessage;
-
-import ch.dissem.bitmessage.entity.*;
-import ch.dissem.bitmessage.entity.payload.Msg;
-import ch.dissem.bitmessage.entity.payload.Pubkey;
-import ch.dissem.bitmessage.ports.Cryptography;
-import ch.dissem.bitmessage.ports.MessageRepository;
-import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
-import ch.dissem.bitmessage.ports.ProofOfWorkRepository;
-import ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import static ch.dissem.bitmessage.InternalContext.NETWORK_EXTRA_BYTES;
-import static ch.dissem.bitmessage.InternalContext.NETWORK_NONCE_TRIALS_PER_BYTE;
-import static ch.dissem.bitmessage.utils.Singleton.cryptography;
-
-/**
- * @author Christian Basler
- */
-public class ProofOfWorkService implements ProofOfWorkEngine.Callback, InternalContext.ContextHolder {
- private final static Logger LOG = LoggerFactory.getLogger(ProofOfWorkService.class);
-
- private Cryptography cryptography;
- private InternalContext ctx;
- private ProofOfWorkRepository powRepo;
- private MessageRepository messageRepo;
-
- public void doMissingProofOfWork(long delayInMilliseconds) {
- final List items = powRepo.getItems();
- if (items.isEmpty()) return;
-
- // Wait for 30 seconds, to let the application start up before putting heavy load on the CPU
- new Timer().schedule(new TimerTask() {
- @Override
- public void run() {
- LOG.info("Doing POW for " + items.size() + " tasks.");
- for (byte[] initialHash : items) {
- Item item = powRepo.getItem(initialHash);
- cryptography.doProofOfWork(item.object, item.nonceTrialsPerByte, item.extraBytes,
- ProofOfWorkService.this);
- }
- }
- }, delayInMilliseconds);
- }
-
- public void doProofOfWork(ObjectMessage object) {
- doProofOfWork(null, object);
- }
-
- public void doProofOfWork(BitmessageAddress recipient, ObjectMessage object) {
- Pubkey pubkey = recipient == null ? null : recipient.getPubkey();
-
- long nonceTrialsPerByte = pubkey == null ? NETWORK_NONCE_TRIALS_PER_BYTE : pubkey.getNonceTrialsPerByte();
- long extraBytes = pubkey == null ? NETWORK_EXTRA_BYTES : pubkey.getExtraBytes();
-
- powRepo.putObject(object, nonceTrialsPerByte, extraBytes);
- if (object.getPayload() instanceof PlaintextHolder) {
- Plaintext plaintext = ((PlaintextHolder) object.getPayload()).getPlaintext();
- plaintext.setInitialHash(cryptography.getInitialHash(object));
- messageRepo.save(plaintext);
- }
- cryptography.doProofOfWork(object, nonceTrialsPerByte, extraBytes, this);
- }
-
- public void doProofOfWorkWithAck(Plaintext plaintext, long expirationTime) {
- final ObjectMessage ack = plaintext.getAckMessage();
- messageRepo.save(plaintext);
- Item item = new Item(ack, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES,
- expirationTime, plaintext);
- powRepo.putObject(item);
- cryptography.doProofOfWork(ack, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES, this);
- }
-
- @Override
- public void onNonceCalculated(byte[] initialHash, byte[] nonce) {
- Item item = powRepo.getItem(initialHash);
- if (item.message == null) {
- ObjectMessage object = item.object;
- object.setNonce(nonce);
- Plaintext plaintext = messageRepo.getMessage(initialHash);
- if (plaintext != null) {
- plaintext.setInventoryVector(object.getInventoryVector());
- plaintext.updateNextTry();
- ctx.getLabeler().markAsSent(plaintext);
- messageRepo.save(plaintext);
- }
- try {
- ctx.getNetworkListener().receive(object);
- } catch (IOException e) {
- LOG.debug(e.getMessage(), e);
- }
- ctx.getInventory().storeObject(object);
- ctx.getNetworkHandler().offer(object.getInventoryVector());
- } else {
- item.message.getAckMessage().setNonce(nonce);
- final ObjectMessage object = new ObjectMessage.Builder()
- .stream(item.message.getStream())
- .expiresTime(item.expirationTime)
- .payload(new Msg(item.message))
- .build();
- if (object.isSigned()) {
- object.sign(item.message.getFrom().getPrivateKey());
- }
- if (object.getPayload() instanceof Encrypted) {
- object.encrypt(item.message.getTo().getPubkey());
- }
- doProofOfWork(item.message.getTo(), object);
- }
- powRepo.removeObject(initialHash);
- }
-
- @Override
- public void setContext(InternalContext ctx) {
- this.ctx = ctx;
- this.cryptography = cryptography();
- this.powRepo = ctx.getProofOfWorkRepository();
- this.messageRepo = ctx.getMessageRepository();
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java
deleted file mode 100644
index 73d9995..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.java
+++ /dev/null
@@ -1,83 +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.entity;
-
-import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * The 'addr' command holds a list of known active Bitmessage nodes.
- */
-public class Addr implements MessagePayload {
- private static final long serialVersionUID = -5117688017050138720L;
-
- private final List addresses;
-
- private Addr(Builder builder) {
- addresses = builder.addresses;
- }
-
- @Override
- public Command getCommand() {
- return Command.ADDR;
- }
-
- public List getAddresses() {
- return addresses;
- }
-
- @Override
- public void write(OutputStream out) throws IOException {
- Encode.varInt(addresses.size(), out);
- for (NetworkAddress address : addresses) {
- address.write(out);
- }
- }
-
- @Override
- public void write(ByteBuffer buffer) {
- Encode.varInt(addresses.size(), buffer);
- for (NetworkAddress address : addresses) {
- address.write(buffer);
- }
- }
-
- public static final class Builder {
- private List addresses = new ArrayList<>();
-
- public Builder addresses(Collection addresses){
- this.addresses.addAll(addresses);
- return this;
- }
-
- public Builder addAddress(final NetworkAddress address) {
- this.addresses.add(address);
- return this;
- }
-
- public Addr build() {
- return new Addr(this);
- }
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java b/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java
deleted file mode 100644
index ce199c4..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/BitmessageAddress.java
+++ /dev/null
@@ -1,277 +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.entity;
-
-import ch.dissem.bitmessage.entity.payload.Pubkey;
-import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
-import ch.dissem.bitmessage.entity.payload.V4Pubkey;
-import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
-import ch.dissem.bitmessage.exception.ApplicationException;
-import ch.dissem.bitmessage.utils.AccessCounter;
-import ch.dissem.bitmessage.utils.Base58;
-import ch.dissem.bitmessage.utils.Bytes;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-import static ch.dissem.bitmessage.utils.Decode.bytes;
-import static ch.dissem.bitmessage.utils.Decode.varInt;
-import static ch.dissem.bitmessage.utils.Singleton.cryptography;
-
-/**
- * A Bitmessage address. Can be a user's private address, an address string without public keys or a recipient's address
- * holding private keys.
- */
-public class BitmessageAddress implements Serializable {
- private static final long serialVersionUID = 2386328540805994064L;
-
- private final long version;
- private final long stream;
- private final byte[] ripe;
- private final byte[] tag;
- /**
- * Used for V4 address encryption. It's easier to just create it regardless of address version.
- */
- private final byte[] publicDecryptionKey;
-
- private String address;
-
- private PrivateKey privateKey;
- private Pubkey pubkey;
-
- private String alias;
- private boolean subscribed;
- private boolean chan;
-
- BitmessageAddress(long version, long stream, byte[] ripe) {
- try {
- this.version = version;
- this.stream = stream;
- this.ripe = ripe;
-
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- Encode.varInt(version, os);
- Encode.varInt(stream, os);
- if (version < 4) {
- byte[] checksum = cryptography().sha512(os.toByteArray(), ripe);
- this.tag = null;
- this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
- } else {
- // for tag and decryption key, the checksum has to be created with 0x00 padding
- byte[] checksum = cryptography().doubleSha512(os.toByteArray(), ripe);
- this.tag = Arrays.copyOfRange(checksum, 32, 64);
- this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
- }
- // but for the address and its checksum they need to be stripped
- int offset = Bytes.numberOfLeadingZeros(ripe);
- os.write(ripe, offset, ripe.length - offset);
- byte[] checksum = cryptography().doubleSha512(os.toByteArray());
- os.write(checksum, 0, 4);
- this.address = "BM-" + Base58.encode(os.toByteArray());
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public BitmessageAddress(Pubkey publicKey) {
- this(publicKey.getVersion(), publicKey.getStream(), publicKey.getRipe());
- this.pubkey = publicKey;
- }
-
- public BitmessageAddress(String address, String passphrase) {
- this(address);
- this.privateKey = new PrivateKey(this, passphrase);
- this.pubkey = this.privateKey.getPubkey();
- if (!Arrays.equals(ripe, privateKey.getPubkey().getRipe())) {
- throw new IllegalArgumentException("Wrong address or passphrase");
- }
- }
-
- public static BitmessageAddress chan(String address, String passphrase) {
- BitmessageAddress result = new BitmessageAddress(address, passphrase);
- result.chan = true;
- return result;
- }
-
- public static BitmessageAddress chan(long stream, String passphrase) {
- PrivateKey privateKey = new PrivateKey(Pubkey.LATEST_VERSION, stream, passphrase);
- BitmessageAddress result = new BitmessageAddress(privateKey);
- result.chan = true;
- return result;
- }
-
- public static List deterministic(String passphrase, int numberOfAddresses,
- long version, long stream, boolean shorter) {
- List result = new ArrayList<>(numberOfAddresses);
- List privateKeys = PrivateKey.deterministic(passphrase, numberOfAddresses, version, stream, shorter);
- for (PrivateKey pk : privateKeys) {
- result.add(new BitmessageAddress(pk));
- }
- return result;
- }
-
- public BitmessageAddress(PrivateKey privateKey) {
- this(privateKey.getPubkey());
- this.privateKey = privateKey;
- }
-
- public BitmessageAddress(String address) {
- try {
- this.address = address;
- byte[] bytes = Base58.decode(address.substring(3));
- ByteArrayInputStream in = new ByteArrayInputStream(bytes);
- AccessCounter counter = new AccessCounter();
- this.version = varInt(in, counter);
- this.stream = varInt(in, counter);
- this.ripe = Bytes.expand(bytes(in, bytes.length - counter.length() - 4), 20);
-
- // test checksum
- byte[] checksum = cryptography().doubleSha512(bytes, bytes.length - 4);
- byte[] expectedChecksum = bytes(in, 4);
- for (int i = 0; i < 4; i++) {
- if (expectedChecksum[i] != checksum[i])
- throw new IllegalArgumentException("Checksum of address failed");
- }
- if (version < 4) {
- checksum = cryptography().sha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
- this.tag = null;
- this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
- } else {
- checksum = cryptography().doubleSha512(Arrays.copyOfRange(bytes, 0, counter.length()), ripe);
- this.tag = Arrays.copyOfRange(checksum, 32, 64);
- this.publicDecryptionKey = Arrays.copyOfRange(checksum, 0, 32);
- }
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public static byte[] calculateTag(long version, long stream, byte[] ripe) {
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- Encode.varInt(version, out);
- Encode.varInt(stream, out);
- out.write(ripe);
- return Arrays.copyOfRange(cryptography().doubleSha512(out.toByteArray()), 32, 64);
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public long getStream() {
- return stream;
- }
-
- public long getVersion() {
- return version;
- }
-
- public Pubkey getPubkey() {
- return pubkey;
- }
-
- public void setPubkey(Pubkey pubkey) {
- if (pubkey instanceof V4Pubkey) {
- if (!Arrays.equals(tag, ((V4Pubkey) pubkey).getTag()))
- throw new IllegalArgumentException("Pubkey has incompatible tag");
- }
- if (!Arrays.equals(ripe, pubkey.getRipe()))
- throw new IllegalArgumentException("Pubkey has incompatible ripe");
- this.pubkey = pubkey;
- }
-
- /**
- * @return the private key used to decrypt Pubkey objects (for v4 addresses) and broadcasts.
- */
- public byte[] getPublicDecryptionKey() {
- return publicDecryptionKey;
- }
-
- public PrivateKey getPrivateKey() {
- return privateKey;
- }
-
- public String getAddress() {
- return address;
- }
-
- public String getAlias() {
- return alias;
- }
-
- public void setAlias(String alias) {
- this.alias = alias;
- }
-
- @Override
- public String toString() {
- return alias == null ? address : alias;
- }
-
- public byte[] getRipe() {
- return ripe;
- }
-
- public byte[] getTag() {
- 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);
- }
-
- public boolean isSubscribed() {
- return subscribed;
- }
-
- public void setSubscribed(boolean subscribed) {
- this.subscribed = subscribed;
- }
-
- public boolean isChan() {
- return chan;
- }
-
- public void setChan(boolean chan) {
- this.chan = chan;
- }
-
- public boolean has(Feature feature) {
- if (pubkey == null || feature == null) {
- return false;
- }
- return feature.isActive(pubkey.getBehaviorBitfield());
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java
deleted file mode 100644
index 439f003..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/CustomMessage.java
+++ /dev/null
@@ -1,111 +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.entity;
-
-import ch.dissem.bitmessage.exception.ApplicationException;
-import ch.dissem.bitmessage.utils.AccessCounter;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.*;
-import java.nio.ByteBuffer;
-
-import static ch.dissem.bitmessage.utils.Decode.bytes;
-import static ch.dissem.bitmessage.utils.Decode.varString;
-
-/**
- * @author Christian Basler
- */
-public class CustomMessage implements MessagePayload {
- private static final long serialVersionUID = -8932056829480326011L;
-
- public static final String COMMAND_ERROR = "ERROR";
-
- private final String command;
- private final byte[] data;
-
- public CustomMessage(String command) {
- this.command = command;
- this.data = null;
- }
-
- public CustomMessage(String command, byte[] data) {
- this.command = command;
- this.data = data;
- }
-
- public static CustomMessage read(InputStream in, int length) throws IOException {
- AccessCounter counter = new AccessCounter();
- return new CustomMessage(varString(in, counter), bytes(in, length - counter.length()));
- }
-
- @Override
- public Command getCommand() {
- return Command.CUSTOM;
- }
-
- public String getCustomCommand() {
- return command;
- }
-
- public byte[] getData() {
- if (data != null) {
- return data;
- } else {
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- write(out);
- return out.toByteArray();
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
- }
-
- @Override
- public void write(OutputStream out) throws IOException {
- if (data != null) {
- Encode.varString(command, out);
- out.write(data);
- } else {
- throw new ApplicationException("Tried to write custom message without data. " +
- "Programmer: did you forget to override #write()?");
- }
- }
-
- @Override
- public void write(ByteBuffer buffer) {
- if (data != null) {
- Encode.varString(command, buffer);
- buffer.put(data);
- } else {
- throw new ApplicationException("Tried to write custom message without data. " +
- "Programmer: did you forget to override #write()?");
- }
- }
-
- public boolean isError() {
- return COMMAND_ERROR.equals(command);
- }
-
- public static CustomMessage error(String message) {
- try {
- return new CustomMessage(COMMAND_ERROR, message.getBytes("UTF-8"));
- } catch (UnsupportedEncodingException e) {
- throw new ApplicationException(e);
- }
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java
deleted file mode 100644
index 7d14fa0..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.java
+++ /dev/null
@@ -1,84 +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.entity;
-
-import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * The 'getdata' command is used to request objects from a node.
- */
-public class GetData implements MessagePayload {
- private static final long serialVersionUID = 1433878785969631061L;
-
- public static final int MAX_INVENTORY_SIZE = 50_000;
-
- List inventory;
-
- private GetData(Builder builder) {
- inventory = builder.inventory;
- }
-
- @Override
- public Command getCommand() {
- return Command.GETDATA;
- }
-
- public List getInventory() {
- return inventory;
- }
-
- @Override
- public void write(OutputStream out) throws IOException {
- Encode.varInt(inventory.size(), out);
- for (InventoryVector iv : inventory) {
- iv.write(out);
- }
- }
-
- @Override
- public void write(ByteBuffer buffer) {
- Encode.varInt(inventory.size(), buffer);
- for (InventoryVector iv : inventory) {
- iv.write(buffer);
- }
- }
-
- public static final class Builder {
- private List inventory = new LinkedList<>();
-
- public Builder addInventoryVector(InventoryVector inventoryVector) {
- this.inventory.add(inventoryVector);
- return this;
- }
-
- public Builder inventory(List inventory) {
- this.inventory = inventory;
- return this;
- }
-
- public GetData build() {
- return new GetData(this);
- }
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java
deleted file mode 100644
index 8d0f592..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.java
+++ /dev/null
@@ -1,82 +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.entity;
-
-import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * The 'inv' command holds up to 50000 inventory vectors, i.e. hashes of inventory items.
- */
-public class Inv implements MessagePayload {
- private static final long serialVersionUID = 3662992522956947145L;
-
- private List inventory;
-
- private Inv(Builder builder) {
- inventory = builder.inventory;
- }
-
- public List getInventory() {
- return inventory;
- }
-
- @Override
- public Command getCommand() {
- return Command.INV;
- }
-
- @Override
- public void write(OutputStream out) throws IOException {
- Encode.varInt(inventory.size(), out);
- for (InventoryVector iv : inventory) {
- iv.write(out);
- }
- }
-
- @Override
- public void write(ByteBuffer buffer) {
- Encode.varInt(inventory.size(), buffer);
- for (InventoryVector iv : inventory) {
- iv.write(buffer);
- }
- }
-
- public static final class Builder {
- private List inventory = new LinkedList<>();
-
- public Builder addInventoryVector(InventoryVector inventoryVector) {
- this.inventory.add(inventoryVector);
- return this;
- }
-
- public Builder inventory(List inventory) {
- this.inventory = inventory;
- return this;
- }
-
- public Inv build() {
- return new Inv(this);
- }
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java
deleted file mode 100644
index f27384e..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.java
+++ /dev/null
@@ -1,151 +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.entity;
-
-import ch.dissem.bitmessage.exception.ApplicationException;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.security.GeneralSecurityException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-
-import static ch.dissem.bitmessage.utils.Singleton.cryptography;
-
-/**
- * A network message is exchanged between two nodes.
- */
-public class NetworkMessage implements Streamable {
- private static final long serialVersionUID = 702708857104464809L;
-
- /**
- * Magic value indicating message origin network, and used to seek to next message when stream state is unknown
- */
- public final static int MAGIC = 0xE9BEB4D9;
- public final static byte[] MAGIC_BYTES = ByteBuffer.allocate(4).putInt(MAGIC).array();
-
- private final MessagePayload payload;
-
- public NetworkMessage(MessagePayload payload) {
- this.payload = payload;
- }
-
- /**
- * First 4 bytes of sha512(payload)
- */
- private byte[] getChecksum(byte[] bytes) throws NoSuchProviderException, NoSuchAlgorithmException {
- byte[] d = cryptography().sha512(bytes);
- return new byte[]{d[0], d[1], d[2], d[3]};
- }
-
- /**
- * The actual data, a message or an object. Not to be confused with objectPayload.
- */
- public MessagePayload getPayload() {
- return payload;
- }
-
- @Override
- public void write(OutputStream out) throws IOException {
- // magic
- Encode.int32(MAGIC, out);
-
- // ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
- String command = payload.getCommand().name().toLowerCase();
- out.write(command.getBytes("ASCII"));
- for (int i = command.length(); i < 12; i++) {
- out.write('\0');
- }
-
- byte[] payloadBytes = Encode.bytes(payload);
-
- // 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
- // larger than this.
- Encode.int32(payloadBytes.length, out);
-
- // checksum
- try {
- out.write(getChecksum(payloadBytes));
- } catch (GeneralSecurityException e) {
- throw new ApplicationException(e);
- }
-
- // message payload
- out.write(payloadBytes);
- }
-
- /**
- * A more efficient implementation of the write method, writing header data to the provided buffer and returning
- * a new buffer containing the payload.
- *
- * @param headerBuffer where the header data is written to (24 bytes)
- * @return a buffer containing the payload, ready to be read.
- */
- public ByteBuffer writeHeaderAndGetPayloadBuffer(ByteBuffer headerBuffer) {
- return ByteBuffer.wrap(writeHeader(headerBuffer));
- }
-
- /**
- * For improved memory efficiency, you should use {@link #writeHeaderAndGetPayloadBuffer(ByteBuffer)}
- * and write the header buffer as well as the returned payload buffer into the channel.
- *
- * @param buffer where everything gets written to. Needs to be large enough for the whole message
- * to be written.
- */
- @Override
- public void write(ByteBuffer buffer) {
- byte[] payloadBytes = writeHeader(buffer);
- buffer.put(payloadBytes);
- }
-
- private byte[] writeHeader(ByteBuffer out) {
- // magic
- Encode.int32(MAGIC, out);
-
- // ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
- String command = payload.getCommand().name().toLowerCase();
- try {
- out.put(command.getBytes("ASCII"));
- } catch (UnsupportedEncodingException e) {
- throw new ApplicationException(e);
- }
- for (int i = command.length(); i < 12; i++) {
- out.put((byte) 0);
- }
-
- byte[] payloadBytes = Encode.bytes(payload);
-
- // 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
- // larger than this.
- Encode.int32(payloadBytes.length, out);
-
- // checksum
- try {
- out.put(getChecksum(payloadBytes));
- } catch (GeneralSecurityException e) {
- throw new ApplicationException(e);
- }
-
- // message payload
- return payloadBytes;
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java b/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java
deleted file mode 100644
index 8e386f7..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/ObjectMessage.java
+++ /dev/null
@@ -1,271 +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.entity;
-
-import ch.dissem.bitmessage.entity.payload.ObjectPayload;
-import ch.dissem.bitmessage.entity.payload.ObjectType;
-import ch.dissem.bitmessage.entity.payload.Pubkey;
-import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
-import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
-import ch.dissem.bitmessage.exception.ApplicationException;
-import ch.dissem.bitmessage.exception.DecryptionFailedException;
-import ch.dissem.bitmessage.utils.Bytes;
-import ch.dissem.bitmessage.utils.Encode;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Objects;
-
-import static ch.dissem.bitmessage.utils.Singleton.cryptography;
-
-/**
- * The 'object' command sends an object that is shared throughout the network.
- */
-public class ObjectMessage implements MessagePayload {
- private static final long serialVersionUID = 2495752480120659139L;
-
- private byte[] nonce;
- private long expiresTime;
- private long objectType;
- /**
- * The object's version
- */
- private long version;
- private long stream;
-
- private ObjectPayload payload;
- private byte[] payloadBytes;
-
- private ObjectMessage(Builder builder) {
- nonce = builder.nonce;
- expiresTime = builder.expiresTime;
- objectType = builder.objectType;
- version = builder.payload.getVersion();
- stream = builder.streamNumber > 0 ? builder.streamNumber : builder.payload.getStream();
- payload = builder.payload;
- }
-
- @Override
- public Command getCommand() {
- return Command.OBJECT;
- }
-
- public byte[] getNonce() {
- return nonce;
- }
-
- public void setNonce(byte[] nonce) {
- this.nonce = nonce;
- }
-
- public long getExpiresTime() {
- return expiresTime;
- }
-
- public long getType() {
- return objectType;
- }
-
- public ObjectPayload getPayload() {
- return payload;
- }
-
- public long getVersion() {
- return version;
- }
-
- public long getStream() {
- return stream;
- }
-
- public InventoryVector getInventoryVector() {
- return InventoryVector.fromHash(
- Bytes.truncate(cryptography().doubleSha512(nonce, getPayloadBytesWithoutNonce()), 32)
- );
- }
-
- private boolean isEncrypted() {
- return payload instanceof Encrypted && !((Encrypted) payload).isDecrypted();
- }
-
- public boolean isSigned() {
- return payload.isSigned();
- }
-
- private byte[] getBytesToSign() {
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- writeHeaderWithoutNonce(out);
- payload.writeBytesToSign(out);
- return out.toByteArray();
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public void sign(PrivateKey key) {
- if (payload.isSigned()) {
- payload.setSignature(cryptography().getSignature(getBytesToSign(), key));
- }
- }
-
- public void decrypt(PrivateKey key) throws IOException, DecryptionFailedException {
- if (payload instanceof Encrypted) {
- ((Encrypted) payload).decrypt(key.getPrivateEncryptionKey());
- }
- }
-
- public void decrypt(byte[] privateEncryptionKey) throws IOException, DecryptionFailedException {
- if (payload instanceof Encrypted) {
- ((Encrypted) payload).decrypt(privateEncryptionKey);
- }
- }
-
- public void encrypt(byte[] publicEncryptionKey) throws IOException {
- if (payload instanceof Encrypted) {
- ((Encrypted) payload).encrypt(publicEncryptionKey);
- }
- }
-
- public void encrypt(Pubkey publicKey) {
- try {
- if (payload instanceof Encrypted) {
- ((Encrypted) payload).encrypt(publicKey.getEncryptionKey());
- }
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public boolean isSignatureValid(Pubkey pubkey) throws IOException {
- if (isEncrypted()) throw new IllegalStateException("Payload must be decrypted first");
- return cryptography().isSignatureValid(getBytesToSign(), payload.getSignature(), pubkey);
- }
-
- @Override
- public void write(OutputStream out) throws IOException {
- if (nonce == null) {
- out.write(new byte[8]);
- } else {
- out.write(nonce);
- }
- out.write(getPayloadBytesWithoutNonce());
- }
-
- @Override
- public void write(ByteBuffer buffer) {
- if (nonce == null) {
- buffer.put(new byte[8]);
- } else {
- buffer.put(nonce);
- }
- buffer.put(getPayloadBytesWithoutNonce());
- }
-
- private void writeHeaderWithoutNonce(OutputStream out) throws IOException {
- Encode.int64(expiresTime, out);
- Encode.int32(objectType, out);
- Encode.varInt(version, out);
- Encode.varInt(stream, out);
- }
-
- public byte[] getPayloadBytesWithoutNonce() {
- try {
- if (payloadBytes == null) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- writeHeaderWithoutNonce(out);
- payload.write(out);
- payloadBytes = out.toByteArray();
- }
- return payloadBytes;
- } catch (IOException e) {
- throw new ApplicationException(e);
- }
- }
-
- public static final class Builder {
- private byte[] nonce;
- private long expiresTime;
- private long objectType = -1;
- private long streamNumber;
- private ObjectPayload payload;
-
- public Builder nonce(byte[] nonce) {
- this.nonce = nonce;
- return this;
- }
-
- public Builder expiresTime(long expiresTime) {
- this.expiresTime = expiresTime;
- return this;
- }
-
- public Builder objectType(long objectType) {
- this.objectType = objectType;
- return this;
- }
-
- public Builder objectType(ObjectType objectType) {
- this.objectType = objectType.getNumber();
- return this;
- }
-
- public Builder stream(long streamNumber) {
- this.streamNumber = streamNumber;
- return this;
- }
-
- public Builder payload(ObjectPayload payload) {
- this.payload = payload;
- if (this.objectType == -1)
- this.objectType = payload.getType().getNumber();
- return this;
- }
-
- public ObjectMessage build() {
- return new ObjectMessage(this);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- ObjectMessage that = (ObjectMessage) o;
-
- return expiresTime == that.expiresTime &&
- objectType == that.objectType &&
- version == that.version &&
- stream == that.stream &&
- Objects.equals(payload, that.payload);
- }
-
- @Override
- public int hashCode() {
- int result = Arrays.hashCode(nonce);
- result = 31 * result + (int) (expiresTime ^ (expiresTime >>> 32));
- result = 31 * result + (int) (objectType ^ (objectType >>> 32));
- result = 31 * result + (int) (version ^ (version >>> 32));
- result = 31 * result + (int) (stream ^ (stream >>> 32));
- result = 31 * result + (payload != null ? payload.hashCode() : 0);
- return result;
- }
-}
diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java
deleted file mode 100644
index 141edfc..0000000
--- a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.java
+++ /dev/null
@@ -1,733 +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.entity;
-
-import ch.dissem.bitmessage.entity.payload.Msg;
-import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
-import ch.dissem.bitmessage.entity.valueobject.ExtendedEncoding;
-import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
-import ch.dissem.bitmessage.entity.valueobject.Label;
-import ch.dissem.bitmessage.entity.valueobject.extended.Attachment;
-import ch.dissem.bitmessage.entity.valueobject.extended.Message;
-import ch.dissem.bitmessage.exception.ApplicationException;
-import ch.dissem.bitmessage.factory.ExtendedEncodingFactory;
-import ch.dissem.bitmessage.factory.Factory;
-import ch.dissem.bitmessage.utils.*;
-
-import java.io.*;
-import java.nio.ByteBuffer;
-import java.util.*;
-import java.util.Collections;
-
-import static ch.dissem.bitmessage.entity.Plaintext.Encoding.EXTENDED;
-import static ch.dissem.bitmessage.entity.Plaintext.Encoding.SIMPLE;
-import static ch.dissem.bitmessage.utils.Singleton.cryptography;
-
-/**
- * The unencrypted message to be sent by 'msg' or 'broadcast'.
- */
-public class Plaintext implements Streamable {
- private static final long serialVersionUID = -5325729856394951079L;
-
- private final Type type;
- private final BitmessageAddress from;
- private final long encoding;
- private final byte[] message;
- private final byte[] ackData;
- private final UUID conversationId;
- private ExtendedEncoding extendedData;
- private ObjectMessage ackMessage;
- private Object id;
- private InventoryVector inventoryVector;
- private BitmessageAddress to;
- private byte[] signature;
- private Status status;
- private Long sent;
- private Long received;
-
- private Set