diff --git a/README.md b/README.md index dcbffa4..75f2b28 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ BitmessageContext ctx = new BitmessageContext.Builder() .powRepo(new JdbcProofOfWorkRepository(jdbcConfig)) .nodeRegistry(new JdbcNodeRegistry(jdbcConfig)) .networkHandler(new NioNetworkHandler()) - .cryptography(BouncyCryptography.INSTANCE) + .cryptography(new BouncyCryptography()) .listener(System.out::println) .build(); ``` diff --git a/build.gradle b/build.gradle index 26aa243..02fa2b4 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,7 @@ subprojects { } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" + compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } test { diff --git a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.kt b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.kt index 175e378..f3ffa6c 100644 --- a/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.kt +++ b/core/src/main/java/ch/dissem/bitmessage/BitmessageContext.kt @@ -58,7 +58,53 @@ import kotlin.properties.Delegates * * The port defaults to 8444 (the default Bitmessage port) */ -class BitmessageContext private constructor(builder: BitmessageContext.Builder) { +class BitmessageContext( + cryptography: Cryptography, + inventory: Inventory, + nodeRegistry: NodeRegistry, + networkHandler: NetworkHandler, + addressRepository: AddressRepository, + messageRepository: MessageRepository, + proofOfWorkRepository: ProofOfWorkRepository, + proofOfWorkEngine: ProofOfWorkEngine = MultiThreadedPOWEngine(), + customCommandHandler: CustomCommandHandler = object : CustomCommandHandler { + override fun handle(request: CustomMessage): MessagePayload? { + BitmessageContext.LOG.debug("Received custom request, but no custom command handler configured.") + return null + } + }, + listener: Listener, + labeler: Labeler = DefaultLabeler(), + port: Int = 8444, + connectionTTL: Long = 30 * MINUTE, + connectionLimit: Int = 150, + sendPubkeyOnIdentityCreation: Boolean, + doMissingProofOfWorkDelayInSeconds: Int = 30 +) { + + private constructor(builder: BitmessageContext.Builder) : this( + builder.cryptography, + builder.inventory, + builder.nodeRegistry, + builder.networkHandler, + builder.addressRepo, + builder.messageRepo, + builder.proofOfWorkRepository, + builder.proofOfWorkEngine ?: MultiThreadedPOWEngine(), + builder.customCommandHandler ?: object : CustomCommandHandler { + override fun handle(request: CustomMessage): MessagePayload? { + BitmessageContext.LOG.debug("Received custom request, but no custom command handler configured.") + return null + } + }, + builder.listener, + builder.labeler ?: DefaultLabeler(), + builder.port, + builder.connectionTTL, + builder.connectionLimit, + builder.sendPubkeyOnIdentityCreation, + builder.doMissingProofOfWorkDelay + ) private val sendPubkeyOnIdentityCreation: Boolean @@ -72,38 +118,10 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) val labeler: Labeler @JvmName("labeler") get - init { - labeler = builder.labeler ?: DefaultLabeler() - internals = InternalContext( - builder.cryptography, - builder.inventory, - builder.nodeRegistry, - builder.networkHandler, - builder.addressRepo, - builder.messageRepo, - builder.proofOfWorkRepository, - builder.proofOfWorkEngine ?: MultiThreadedPOWEngine(), - builder.customCommandHandler ?: object : CustomCommandHandler { - override fun handle(request: CustomMessage): MessagePayload? { - LOG.debug("Received custom request, but no custom command handler configured.") - return null - } - }, - builder.listener, - labeler, - builder.port, - builder.connectionTTL, - builder.connectionLimit - ) - internals.proofOfWorkService.doMissingProofOfWork(30000) // TODO: this should be configurable - sendPubkeyOnIdentityCreation = builder.sendPubkeyOnIdentityCreation - (builder.listener as? Listener.WithContext)?.setContext(this) - } - - val addresses: AddressRepository = internals.addressRepository + val addresses: AddressRepository @JvmName("addresses") get - val messages: MessageRepository = internals.messageRepository + val messages: MessageRepository @JvmName("messages") get fun createIdentity(shorter: Boolean, vararg features: Feature): BitmessageAddress { @@ -285,10 +303,9 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) fun addContact(contact: BitmessageAddress) { internals.addressRepository.save(contact) if (contact.pubkey == null) { - internals.addressRepository.getAddress(contact.address)?.let { - if (it.pubkey == null) { - internals.requestPubkey(contact) - } + // If it already existed, the saved contact might have the public key + if (internals.addressRepository.getAddress(contact.address)!!.pubkey == null) { + internals.requestPubkey(contact) } } } @@ -300,13 +317,13 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) } private fun tryToFindBroadcastsForAddress(address: BitmessageAddress) { - for (`object` in internals.inventory.getObjects(address.stream, Broadcast.getVersion(address), ObjectType.BROADCAST)) { + for (objectMessage in internals.inventory.getObjects(address.stream, Broadcast.getVersion(address), ObjectType.BROADCAST)) { try { - val broadcast = `object`.payload as Broadcast + val broadcast = objectMessage.payload as Broadcast 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. - internals.networkListener.receive(`object`) + internals.networkListener.receive(objectMessage) } catch (ignore: DecryptionFailedException) { } catch (e: Exception) { LOG.debug(e.message, e) @@ -348,6 +365,7 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) internal var connectionLimit = 150 internal var connectionTTL = 30 * MINUTE internal var sendPubkeyOnIdentityCreation = true + internal var doMissingProofOfWorkDelay = 30 fun port(port: Int): Builder { this.port = port @@ -409,6 +427,7 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) return this } + @JvmName("kotlinListener") fun listener(listener: (Plaintext) -> Unit): Builder { this.listener = object : Listener { override fun receive(plaintext: Plaintext) { @@ -428,6 +447,10 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) return this } + fun doMissingProofOfWorkDelay(seconds: Int) { + this.doMissingProofOfWorkDelay = seconds + } + /** * By default a client will send the public key when an identity is being created. On weaker devices * this behaviour might not be desirable. @@ -438,18 +461,34 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder) } fun build(): BitmessageContext { - nonNull("inventory", inventory) - nonNull("nodeRegistry", nodeRegistry) - nonNull("networkHandler", networkHandler) - nonNull("addressRepo", addressRepo) - nonNull("messageRepo", messageRepo) - nonNull("proofOfWorkRepo", proofOfWorkRepository) return BitmessageContext(this) } + } - private fun nonNull(name: String, o: Any?) { - if (o == null) throw IllegalStateException(name + " must not be null") - } + + init { + this.labeler = labeler + this.internals = InternalContext( + cryptography, + inventory, + nodeRegistry, + networkHandler, + addressRepository, + messageRepository, + proofOfWorkRepository, + proofOfWorkEngine, + customCommandHandler, + listener, + labeler, + port, + connectionTTL, + connectionLimit + ) + this.addresses = addressRepository + this.messages = messageRepository + this.sendPubkeyOnIdentityCreation = sendPubkeyOnIdentityCreation + (listener as? Listener.WithContext)?.setContext(this) + internals.proofOfWorkService.doMissingProofOfWork(doMissingProofOfWorkDelayInSeconds * 1000L) } companion object { diff --git a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.kt b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.kt index 35a7628..37c2a75 100644 --- a/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.kt +++ b/core/src/main/java/ch/dissem/bitmessage/DefaultMessageListener.kt @@ -25,6 +25,7 @@ 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 ch.dissem.bitmessage.utils.Strings.hex import org.slf4j.LoggerFactory import java.util.* @@ -32,23 +33,23 @@ internal open class DefaultMessageListener( private val labeler: Labeler, private val listener: BitmessageContext.Listener ) : NetworkHandler.MessageListener { - private var ctx by InternalContext + private var ctx by InternalContext.lateinit - override fun receive(`object`: ObjectMessage) { - val payload = `object`.payload + override fun receive(objectMessage: ObjectMessage) { + val payload = objectMessage.payload when (payload.type) { ObjectType.GET_PUBKEY -> { - receive(`object`, payload as GetPubkey) + receive(objectMessage, payload as GetPubkey) } ObjectType.PUBKEY -> { - receive(`object`, payload as Pubkey) + receive(objectMessage, payload as Pubkey) } ObjectType.MSG -> { - receive(`object`, payload as Msg) + receive(objectMessage, payload as Msg) } ObjectType.BROADCAST -> { - receive(`object`, payload as Broadcast) + receive(objectMessage, payload as Broadcast) } null -> { if (payload is GenericPayload) { @@ -61,30 +62,33 @@ internal open class DefaultMessageListener( } } - protected fun receive(`object`: ObjectMessage, getPubkey: GetPubkey) { + protected fun receive(objectMessage: ObjectMessage, getPubkey: GetPubkey) { val identity = ctx.addressRepository.findIdentity(getPubkey.ripeTag) if (identity != null && identity.privateKey != 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`.stream) + ctx.sendPubkey(identity, objectMessage.stream) } } - protected fun receive(`object`: ObjectMessage, pubkey: Pubkey) { - val address: BitmessageAddress? + protected fun receive(objectMessage: ObjectMessage, pubkey: Pubkey) { try { if (pubkey is V4Pubkey) { - address = ctx.addressRepository.findContact(pubkey.tag) - if (address != null) { - pubkey.decrypt(address.publicDecryptionKey) + ctx.addressRepository.findContact(pubkey.tag)?.let { + if (it.pubkey == null) { + pubkey.decrypt(it.publicDecryptionKey) + updatePubkey(it, pubkey) + } } } else { - address = ctx.addressRepository.findContact(pubkey.ripe) + ctx.addressRepository.findContact(pubkey.ripe)?.let { + if (it.pubkey == null) { + updatePubkey(it, pubkey) + } + } } - if (address != null && address.pubkey == null) { - updatePubkey(address, pubkey) - } - } catch (_: DecryptionFailedException) {} + } catch (_: DecryptionFailedException) { + } } @@ -101,19 +105,20 @@ internal open class DefaultMessageListener( } } - protected fun receive(`object`: ObjectMessage, msg: Msg) { + protected fun receive(objectMessage: ObjectMessage, msg: Msg) { for (identity in ctx.addressRepository.getIdentities()) { try { msg.decrypt(identity.privateKey!!.privateEncryptionKey) val plaintext = msg.plaintext!! plaintext.to = identity - if (!`object`.isSignatureValid(plaintext.from.pubkey!!)) { - LOG.warn("Msg with IV " + `object`.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.") + if (!objectMessage.isSignatureValid(plaintext.from.pubkey!!)) { + LOG.warn("Msg with IV " + objectMessage.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.") } else { - receive(`object`.inventoryVector, plaintext) + receive(objectMessage.inventoryVector, plaintext) } break - } catch (_: DecryptionFailedException) {} + } catch (_: DecryptionFailedException) { + } } } @@ -122,11 +127,11 @@ internal open class DefaultMessageListener( ctx.messageRepository.getMessageForAck(ack.data)?.let { ctx.labeler.markAsAcknowledged(it) ctx.messageRepository.save(it) - } + } ?: LOG.debug("Message not found for ack ${hex(ack.data)}") } } - protected fun receive(`object`: ObjectMessage, broadcast: Broadcast) { + protected fun receive(objectMessage: ObjectMessage, broadcast: Broadcast) { val tag = if (broadcast is V5Broadcast) broadcast.tag else null for (subscription in ctx.addressRepository.getSubscriptions(broadcast.version)) { if (tag != null && !Arrays.equals(tag, subscription.tag)) { @@ -134,12 +139,13 @@ internal open class DefaultMessageListener( } try { broadcast.decrypt(subscription.publicDecryptionKey) - if (!`object`.isSignatureValid(broadcast.plaintext!!.from.pubkey!!)) { - LOG.warn("Broadcast with IV " + `object`.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.") + if (!objectMessage.isSignatureValid(broadcast.plaintext!!.from.pubkey!!)) { + LOG.warn("Broadcast with IV " + objectMessage.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.") } else { - receive(`object`.inventoryVector, broadcast.plaintext!!) + receive(objectMessage.inventoryVector, broadcast.plaintext!!) } - } catch (_: DecryptionFailedException) {} + } catch (_: DecryptionFailedException) { + } } } @@ -158,7 +164,7 @@ internal open class DefaultMessageListener( msg.ackMessage?.let { ctx.inventory.storeObject(it) ctx.networkHandler.offer(it.inventoryVector) - } + } ?: LOG.debug("ack message expected") } } diff --git a/core/src/main/java/ch/dissem/bitmessage/InternalContext.kt b/core/src/main/java/ch/dissem/bitmessage/InternalContext.kt index e36a8ac..62bba56 100644 --- a/core/src/main/java/ch/dissem/bitmessage/InternalContext.kt +++ b/core/src/main/java/ch/dissem/bitmessage/InternalContext.kt @@ -28,7 +28,6 @@ import ch.dissem.bitmessage.utils.UnixTime import org.slf4j.LoggerFactory import java.util.* import java.util.concurrent.Executors -import kotlin.properties.Delegates import kotlin.reflect.KProperty /** @@ -68,7 +67,8 @@ class InternalContext( get() = _streams.toLongArray() init { - instance = this + lateinit.instance = this + lateinit = ContextDelegate() Singleton.initialize(cryptography) // TODO: streams of new identities and subscriptions should also be added. This works only after a restart. @@ -102,24 +102,24 @@ class InternalContext( val recipient = to ?: from val expires = UnixTime.now + timeToLive LOG.info("Expires at " + expires) - val `object` = ObjectMessage( + val objectMessage = ObjectMessage( stream = recipient.stream, expiresTime = expires, payload = payload ) - if (`object`.isSigned) { - `object`.sign( + if (objectMessage.isSigned) { + objectMessage.sign( from.privateKey ?: throw IllegalArgumentException("The given sending address is no identity") ) } if (payload is Broadcast) { payload.encrypt() } else if (payload is Encrypted) { - `object`.encrypt( + objectMessage.encrypt( recipient.pubkey ?: throw IllegalArgumentException("The public key for the recipient isn't available") ) } - proofOfWorkService.doProofOfWork(to, `object`) + proofOfWorkService.doProofOfWork(to, objectMessage) } fun sendPubkey(identity: BitmessageAddress, targetStream: Long) { @@ -163,12 +163,11 @@ class InternalContext( } val expires = UnixTime.now + TTL.getpubkey - LOG.info("Expires at " + expires) - val payload = GetPubkey(contact) + LOG.info("Expires at $expires") val request = ObjectMessage( stream = contact.stream, expiresTime = expires, - payload = payload + payload = GetPubkey(contact) ) proofOfWorkService.doProofOfWork(request) } @@ -179,14 +178,14 @@ class InternalContext( address.alias = it.alias address.isSubscribed = it.isSubscribed } - for (`object` in inventory.getObjects(address.stream, address.version, ObjectType.PUBKEY)) { + for (objectMessage in inventory.getObjects(address.stream, address.version, ObjectType.PUBKEY)) { try { - val pubkey = `object`.payload as Pubkey + val pubkey = objectMessage.payload as Pubkey if (address.version == 4L) { val v4Pubkey = pubkey as V4Pubkey if (Arrays.equals(address.tag, v4Pubkey.tag)) { v4Pubkey.decrypt(address.publicDecryptionKey) - if (`object`.isSignatureValid(v4Pubkey)) { + if (objectMessage.isSignatureValid(v4Pubkey)) { address.pubkey = v4Pubkey addressRepository.save(address) break @@ -219,17 +218,19 @@ class InternalContext( fun setContext(context: InternalContext) } + class ContextDelegate { + internal lateinit var instance: InternalContext + operator fun getValue(thisRef: Any?, property: KProperty<*>) = instance + operator fun setValue(thisRef: Any?, property: KProperty<*>, value: InternalContext) {} + } + companion object { private val LOG = LoggerFactory.getLogger(InternalContext::class.java) @JvmField val NETWORK_NONCE_TRIALS_PER_BYTE: Long = 1000 @JvmField val NETWORK_EXTRA_BYTES: Long = 1000 - private var instance: InternalContext by Delegates.notNull() - - operator fun getValue(thisRef: Any?, property: KProperty<*>) = instance - operator fun setValue(thisRef: Any?, property: KProperty<*>, value: InternalContext) { - instance = value - } + var lateinit = ContextDelegate() + private set } } diff --git a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.kt b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.kt index 2472d67..67d6637 100644 --- a/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.kt +++ b/core/src/main/java/ch/dissem/bitmessage/ProofOfWorkService.kt @@ -22,6 +22,7 @@ import ch.dissem.bitmessage.entity.* import ch.dissem.bitmessage.entity.payload.Msg import ch.dissem.bitmessage.ports.ProofOfWorkEngine import ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item +import ch.dissem.bitmessage.utils.Strings import org.slf4j.LoggerFactory import java.io.IOException import java.util.* @@ -31,7 +32,7 @@ import java.util.* */ class ProofOfWorkService : ProofOfWorkEngine.Callback { - private val ctx by InternalContext + private val ctx by InternalContext.lateinit private val cryptography by lazy { ctx.cryptography } private val powRepo by lazy { ctx.proofOfWorkRepository } private val messageRepo by lazy { ctx.messageRepository } @@ -45,75 +46,69 @@ class ProofOfWorkService : ProofOfWorkEngine.Callback { override fun run() { LOG.info("Doing POW for " + items.size + " tasks.") for (initialHash in items) { - val (`object`, nonceTrialsPerByte, extraBytes) = powRepo.getItem(initialHash) - cryptography.doProofOfWork(`object`, nonceTrialsPerByte, extraBytes, + val (objectMessage, nonceTrialsPerByte, extraBytes) = powRepo.getItem(initialHash) + cryptography.doProofOfWork(objectMessage, nonceTrialsPerByte, extraBytes, this@ProofOfWorkService) } } }, delayInMilliseconds) } - fun doProofOfWork(`object`: ObjectMessage) { - doProofOfWork(null, `object`) + fun doProofOfWork(objectMessage: ObjectMessage) { + doProofOfWork(null, objectMessage) } - fun doProofOfWork(recipient: BitmessageAddress?, `object`: ObjectMessage) { + fun doProofOfWork(recipient: BitmessageAddress?, objectMessage: ObjectMessage) { val pubkey = recipient?.pubkey val nonceTrialsPerByte = pubkey?.nonceTrialsPerByte ?: NETWORK_NONCE_TRIALS_PER_BYTE val extraBytes = pubkey?.extraBytes ?: NETWORK_EXTRA_BYTES - powRepo.putObject(`object`, nonceTrialsPerByte, extraBytes) - if (`object`.payload is PlaintextHolder) { - `object`.payload.plaintext?.let { - it.initialHash = cryptography.getInitialHash(`object`) + powRepo.putObject(objectMessage, nonceTrialsPerByte, extraBytes) + if (objectMessage.payload is PlaintextHolder) { + objectMessage.payload.plaintext?.let { + it.initialHash = cryptography.getInitialHash(objectMessage) messageRepo.save(it) - } + } ?: LOG.error("PlaintextHolder without Plaintext shouldn't make it to the POW") } - cryptography.doProofOfWork(`object`, nonceTrialsPerByte, extraBytes, this) + cryptography.doProofOfWork(objectMessage, nonceTrialsPerByte, extraBytes, this) } fun doProofOfWorkWithAck(plaintext: Plaintext, expirationTime: Long) { - val ack = plaintext.ackMessage + val ack = plaintext.ackMessage!! messageRepo.save(plaintext) - val item = Item(ack!!, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES, + val item = 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 fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) { - val (`object`, _, _, expirationTime, message) = powRepo.getItem(initialHash) + val (objectMessage, _, _, expirationTime, message) = powRepo.getItem(initialHash) if (message == null) { - `object`.nonce = nonce + objectMessage.nonce = nonce messageRepo.getMessage(initialHash)?.let { - it.inventoryVector = `object`.inventoryVector + it.inventoryVector = objectMessage.inventoryVector it.updateNextTry() ctx.labeler.markAsSent(it) messageRepo.save(it) } - try { - ctx.networkListener.receive(`object`) - } catch (e: IOException) { - LOG.debug(e.message, e) - } - - ctx.inventory.storeObject(`object`) - ctx.networkHandler.offer(`object`.inventoryVector) + ctx.inventory.storeObject(objectMessage) + ctx.networkHandler.offer(objectMessage.inventoryVector) } else { message.ackMessage!!.nonce = nonce - val `object` = ObjectMessage.Builder() + val newObjectMessage = ObjectMessage.Builder() .stream(message.stream) .expiresTime(expirationTime!!) .payload(Msg(message)) .build() - if (`object`.isSigned) { - `object`.sign(message.from.privateKey!!) + if (newObjectMessage.isSigned) { + newObjectMessage.sign(message.from.privateKey!!) } - if (`object`.payload is Encrypted) { - `object`.encrypt(message.to!!.pubkey!!) + if (newObjectMessage.payload is Encrypted) { + newObjectMessage.encrypt(message.to!!.pubkey!!) } - doProofOfWork(message.to, `object`) + doProofOfWork(message.to, newObjectMessage) } powRepo.removeObject(initialHash) } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.kt b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.kt index 0e7e8f6..056dd63 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Addr.kt +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Addr.kt @@ -28,14 +28,14 @@ data class Addr constructor(val addresses: List) : MessagePayloa override val command: MessagePayload.Command = MessagePayload.Command.ADDR override fun write(out: OutputStream) { - Encode.varInt(addresses.size.toLong(), out) + Encode.varInt(addresses.size, out) for (address in addresses) { address.write(out) } } override fun write(buffer: ByteBuffer) { - Encode.varInt(addresses.size.toLong(), buffer) + Encode.varInt(addresses.size, buffer) for (address in addresses) { address.write(buffer) } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.kt b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.kt index 62fab2b..feebea1 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/GetData.kt +++ b/core/src/main/java/ch/dissem/bitmessage/entity/GetData.kt @@ -29,14 +29,14 @@ class GetData constructor(var inventory: List) : MessagePayload override val command: MessagePayload.Command = MessagePayload.Command.GETDATA override fun write(out: OutputStream) { - Encode.varInt(inventory.size.toLong(), out) + Encode.varInt(inventory.size, out) for (iv in inventory) { iv.write(out) } } override fun write(buffer: ByteBuffer) { - Encode.varInt(inventory.size.toLong(), buffer) + Encode.varInt(inventory.size, buffer) for (iv in inventory) { iv.write(buffer) } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.kt b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.kt index 42f963f..b0c5af9 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Inv.kt +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Inv.kt @@ -29,14 +29,14 @@ class Inv constructor(val inventory: List) : MessagePayload { override val command: MessagePayload.Command = MessagePayload.Command.INV override fun write(out: OutputStream) { - Encode.varInt(inventory.size.toLong(), out) + Encode.varInt(inventory.size, out) for (iv in inventory) { iv.write(out) } } override fun write(buffer: ByteBuffer) { - Encode.varInt(inventory.size.toLong(), buffer) + Encode.varInt(inventory.size, buffer) for (iv in inventory) { iv.write(buffer) } diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.kt b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.kt index 3b5369e..d0c427a 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.kt +++ b/core/src/main/java/ch/dissem/bitmessage/entity/NetworkMessage.kt @@ -43,7 +43,7 @@ data class NetworkMessage( @Throws(IOException::class) override fun write(out: OutputStream) { // magic - Encode.int32(MAGIC.toLong(), out) + Encode.int32(MAGIC, out) // ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected) val command = payload.command.name.toLowerCase() @@ -57,7 +57,7 @@ data class NetworkMessage( // 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.size.toLong(), out) + Encode.int32(payloadBytes.size, out) // checksum out.write(getChecksum(payloadBytes)) @@ -92,7 +92,7 @@ data class NetworkMessage( private fun writeHeader(out: ByteBuffer): ByteArray { // magic - Encode.int32(MAGIC.toLong(), out) + Encode.int32(MAGIC, out) // ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected) val command = payload.command.name.toLowerCase() @@ -107,7 +107,7 @@ data class NetworkMessage( // 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.size.toLong(), out) + Encode.int32(payloadBytes.size, out) // checksum out.put(getChecksum(payloadBytes)) diff --git a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.kt b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.kt index fc4ee0a..462ae83 100644 --- a/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.kt +++ b/core/src/main/java/ch/dissem/bitmessage/entity/Plaintext.kt @@ -17,6 +17,7 @@ package ch.dissem.bitmessage.entity import ch.dissem.bitmessage.entity.Plaintext.Encoding.* +import ch.dissem.bitmessage.entity.Plaintext.Type.MSG import ch.dissem.bitmessage.entity.payload.Msg import ch.dissem.bitmessage.entity.payload.Pubkey.Feature import ch.dissem.bitmessage.entity.valueobject.ExtendedEncoding @@ -38,10 +39,20 @@ import kotlin.collections.HashSet fun message(encoding: Plaintext.Encoding, subject: String, body: String): ByteArray = when (encoding) { SIMPLE -> "Subject:$subject\nBody:$body".toByteArray() EXTENDED -> Message.Builder().subject(subject).body(body).build().zip() - TRIVIAL -> (subject+body).toByteArray() + TRIVIAL -> (subject + body).toByteArray() IGNORE -> ByteArray(0) } +fun ackData(type: Plaintext.Type, ackData: ByteArray?): ByteArray? { + if (ackData != null) { + return ackData + } else if (type == MSG) { + return cryptography().randomBytes(Msg.ACK_LENGTH) + } else { + return null + } +} + /** * The unencrypted message to be sent by 'msg' or 'broadcast'. */ @@ -52,7 +63,7 @@ class Plaintext private constructor( val encodingCode: Long, val message: ByteArray, val ackData: ByteArray?, - ackMessage: Lazy, + ackMessage: Lazy = lazy { Factory.createAck(from, ackData, ttl) }, val conversationId: UUID = UUID.randomUUID(), var inventoryVector: InventoryVector? = null, var signature: ByteArray? = null, @@ -121,7 +132,7 @@ class Plaintext private constructor( to: BitmessageAddress?, encoding: Encoding, message: ByteArray, - ackData: ByteArray = cryptography().randomBytes(Msg.ACK_LENGTH), + ackData: ByteArray? = null, conversationId: UUID = UUID.randomUUID(), inventoryVector: InventoryVector? = null, signature: ByteArray? = null, @@ -131,21 +142,20 @@ class Plaintext private constructor( labels: MutableSet