Refactored to use StreamableWriter
Bumped the msgpack library to 2.0.1 (the 2.0.0 build was fubar)
This commit is contained in:
parent
ece9cd8667
commit
8cbdce6eac
@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.1.4-3'
|
ext.kotlin_version = '1.1.60'
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@ -13,12 +13,12 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
apply plugin: 'io.spring.dependency-management'
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'maven'
|
apply plugin: 'maven'
|
||||||
apply plugin: 'signing'
|
apply plugin: 'signing'
|
||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
apply plugin: 'gitflow-version'
|
apply plugin: 'gitflow-version'
|
||||||
apply plugin: 'io.spring.dependency-management'
|
|
||||||
apply plugin: 'com.github.ben-manes.versions'
|
apply plugin: 'com.github.ben-manes.versions'
|
||||||
|
|
||||||
sourceCompatibility = 1.7
|
sourceCompatibility = 1.7
|
||||||
@ -138,7 +138,7 @@ subprojects {
|
|||||||
entry 'slf4j-simple'
|
entry 'slf4j-simple'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependency 'ch.dissem.msgpack:msgpack:2.0.0'
|
dependency 'ch.dissem.msgpack:msgpack:2.0.1'
|
||||||
dependency 'org.bouncycastle:bcprov-jdk15on:1.57'
|
dependency 'org.bouncycastle:bcprov-jdk15on:1.57'
|
||||||
dependency 'com.madgag.spongycastle:prov:1.56.0.0'
|
dependency 'com.madgag.spongycastle:prov:1.56.0.0'
|
||||||
dependency 'org.apache.commons:commons-lang3:3.6'
|
dependency 'org.apache.commons:commons-lang3:3.6'
|
||||||
|
@ -25,10 +25,10 @@ artifacts {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'org.slf4j:slf4j-api'
|
compile 'org.slf4j:slf4j-api'
|
||||||
compile 'ch.dissem.msgpack:msgpack:1.0.0'
|
compile 'ch.dissem.msgpack:msgpack'
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit'
|
||||||
testCompile 'org.hamcrest:hamcrest-library:1.3'
|
testCompile 'org.hamcrest:hamcrest-library'
|
||||||
testCompile 'com.nhaarman:mockito-kotlin:1.5.0'
|
testCompile 'com.nhaarman:mockito-kotlin'
|
||||||
testCompile project(':cryptography-bc')
|
testCompile project(':cryptography-bc')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +272,7 @@ class BitmessageContext(
|
|||||||
*/
|
*/
|
||||||
fun cleanup() {
|
fun cleanup() {
|
||||||
internals.inventory.cleanup()
|
internals.inventory.cleanup()
|
||||||
|
internals.nodeRegistry.cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,19 +25,28 @@ import java.nio.ByteBuffer
|
|||||||
* The 'addr' command holds a list of known active Bitmessage nodes.
|
* The 'addr' command holds a list of known active Bitmessage nodes.
|
||||||
*/
|
*/
|
||||||
data class Addr constructor(val addresses: List<NetworkAddress>) : MessagePayload {
|
data class Addr constructor(val addresses: List<NetworkAddress>) : MessagePayload {
|
||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.ADDR
|
override val command: MessagePayload.Command = MessagePayload.Command.ADDR
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: Addr
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
Encode.varInt(addresses.size, out)
|
Encode.varInt(item.addresses.size, out)
|
||||||
for (address in addresses) {
|
for (address in item.addresses) {
|
||||||
address.write(out)
|
address.writer().write(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
Encode.varInt(addresses.size, buffer)
|
Encode.varInt(item.addresses.size, buffer)
|
||||||
for (address in addresses) {
|
for (address in item.addresses) {
|
||||||
address.write(buffer)
|
address.writer().write(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,22 +33,26 @@ open class CustomMessage(val customCommand: String, private val data: ByteArray?
|
|||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.CUSTOM
|
override val command: MessagePayload.Command = MessagePayload.Command.CUSTOM
|
||||||
|
|
||||||
val isError: Boolean
|
val isError = COMMAND_ERROR == customCommand
|
||||||
|
|
||||||
fun getData(): ByteArray {
|
fun getData(): ByteArray {
|
||||||
if (data != null) {
|
return data ?: {
|
||||||
return data
|
|
||||||
} else {
|
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
write(out)
|
writer().write(out)
|
||||||
return out.toByteArray()
|
out.toByteArray()
|
||||||
}
|
}.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
protected open class Writer(
|
||||||
|
private val item: CustomMessage
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
if (data != null) {
|
if (item.data != null) {
|
||||||
Encode.varString(customCommand, out)
|
Encode.varString(item.customCommand, out)
|
||||||
out.write(data)
|
out.write(item.data)
|
||||||
} else {
|
} else {
|
||||||
throw ApplicationException("Tried to write custom message without data. "
|
throw ApplicationException("Tried to write custom message without data. "
|
||||||
+ "Programmer: did you forget to override #write()?")
|
+ "Programmer: did you forget to override #write()?")
|
||||||
@ -56,15 +60,17 @@ open class CustomMessage(val customCommand: String, private val data: ByteArray?
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
if (data != null) {
|
if (item.data != null) {
|
||||||
Encode.varString(customCommand, buffer)
|
Encode.varString(item.customCommand, buffer)
|
||||||
buffer.put(data)
|
buffer.put(item.data)
|
||||||
} else {
|
} else {
|
||||||
throw ApplicationException("Tried to write custom message without data. "
|
throw ApplicationException("Tried to write custom message without data. "
|
||||||
+ "Programmer: did you forget to override #write()?")
|
+ "Programmer: did you forget to override #write()?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val COMMAND_ERROR = "ERROR"
|
val COMMAND_ERROR = "ERROR"
|
||||||
|
|
||||||
@ -75,12 +81,6 @@ open class CustomMessage(val customCommand: String, private val data: ByteArray?
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun error(message: String): CustomMessage {
|
fun error(message: String) = CustomMessage(COMMAND_ERROR, message.toByteArray(charset("UTF-8")))
|
||||||
return CustomMessage(COMMAND_ERROR, message.toByteArray(charset("UTF-8")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.isError = COMMAND_ERROR == customCommand
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,30 @@ class GetData constructor(var inventory: List<InventoryVector>) : MessagePayload
|
|||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.GETDATA
|
override val command: MessagePayload.Command = MessagePayload.Command.GETDATA
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: GetData
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
Encode.varInt(inventory.size, out)
|
Encode.varInt(item.inventory.size, out)
|
||||||
for (iv in inventory) {
|
for (iv in item.inventory) {
|
||||||
iv.write(out)
|
iv.writer().write(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
Encode.varInt(inventory.size, buffer)
|
Encode.varInt(item.inventory.size, buffer)
|
||||||
for (iv in inventory) {
|
for (iv in item.inventory) {
|
||||||
iv.write(buffer)
|
iv.writer().write(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val MAX_INVENTORY_SIZE = 50000
|
@JvmField
|
||||||
|
val MAX_INVENTORY_SIZE = 50000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,17 +28,25 @@ class Inv constructor(val inventory: List<InventoryVector>) : MessagePayload {
|
|||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.INV
|
override val command: MessagePayload.Command = MessagePayload.Command.INV
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: Inv
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
Encode.varInt(inventory.size, out)
|
Encode.varInt(item.inventory.size, out)
|
||||||
for (iv in inventory) {
|
for (iv in item.inventory) {
|
||||||
iv.write(out)
|
iv.writer().write(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
Encode.varInt(inventory.size, buffer)
|
Encode.varInt(item.inventory.size, buffer)
|
||||||
for (iv in inventory) {
|
for (iv in item.inventory) {
|
||||||
iv.write(buffer)
|
iv.writer().write(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ package ch.dissem.bitmessage.entity
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.utils.Encode
|
import ch.dissem.bitmessage.utils.Encode
|
||||||
import ch.dissem.bitmessage.utils.Singleton.cryptography
|
import ch.dissem.bitmessage.utils.Singleton.cryptography
|
||||||
import java.io.IOException
|
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
@ -32,26 +31,24 @@ data class NetworkMessage(
|
|||||||
val payload: MessagePayload
|
val payload: MessagePayload
|
||||||
) : Streamable {
|
) : Streamable {
|
||||||
|
|
||||||
/**
|
override fun writer(): Writer = Writer(this)
|
||||||
* First 4 bytes of sha512(payload)
|
|
||||||
*/
|
class Writer internal constructor(
|
||||||
private fun getChecksum(bytes: ByteArray): ByteArray {
|
private val item: NetworkMessage
|
||||||
val d = cryptography().sha512(bytes)
|
) : StreamableWriter {
|
||||||
return byteArrayOf(d[0], d[1], d[2], d[3])
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
// magic
|
// magic
|
||||||
Encode.int32(MAGIC, out)
|
Encode.int32(MAGIC, out)
|
||||||
|
|
||||||
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
|
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
|
||||||
val command = payload.command.name.toLowerCase()
|
val command = item.payload.command.name.toLowerCase()
|
||||||
out.write(command.toByteArray(charset("ASCII")))
|
out.write(command.toByteArray(charset("ASCII")))
|
||||||
for (i in command.length..11) {
|
for (i in command.length..11) {
|
||||||
out.write(0x0)
|
out.write(0x0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val payloadBytes = Encode.bytes(payload)
|
val payloadBytes = Encode.bytes(item.payload)
|
||||||
|
|
||||||
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
|
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
|
||||||
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
|
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
|
||||||
@ -94,14 +91,14 @@ data class NetworkMessage(
|
|||||||
Encode.int32(MAGIC, out)
|
Encode.int32(MAGIC, out)
|
||||||
|
|
||||||
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
|
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
|
||||||
val command = payload.command.name.toLowerCase()
|
val command = item.payload.command.name.toLowerCase()
|
||||||
out.put(command.toByteArray(charset("ASCII")))
|
out.put(command.toByteArray(charset("ASCII")))
|
||||||
|
|
||||||
for (i in command.length..11) {
|
for (i in command.length..11) {
|
||||||
out.put(0.toByte())
|
out.put(0.toByte())
|
||||||
}
|
}
|
||||||
|
|
||||||
val payloadBytes = Encode.bytes(payload)
|
val payloadBytes = Encode.bytes(item.payload)
|
||||||
|
|
||||||
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
|
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
|
||||||
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
|
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
|
||||||
@ -115,6 +112,16 @@ data class NetworkMessage(
|
|||||||
return payloadBytes
|
return payloadBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First 4 bytes of sha512(payload)
|
||||||
|
*/
|
||||||
|
private fun getChecksum(bytes: ByteArray): ByteArray {
|
||||||
|
val d = cryptography().sha512(bytes)
|
||||||
|
return byteArrayOf(d[0], d[1], d[2], d[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Magic value indicating message origin network, and used to seek to next message when stream state is unknown
|
* Magic value indicating message origin network, and used to seek to next message when stream state is unknown
|
||||||
|
@ -81,8 +81,8 @@ data class ObjectMessage(
|
|||||||
get() {
|
get() {
|
||||||
try {
|
try {
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
writeHeaderWithoutNonce(out)
|
writer.writeHeaderWithoutNonce(out)
|
||||||
payload.writeBytesToSign(out)
|
payload.writer().writeBytesToSign(out)
|
||||||
return out.toByteArray()
|
return out.toByteArray()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
throw ApplicationException(e)
|
throw ApplicationException(e)
|
||||||
@ -131,28 +131,37 @@ data class ObjectMessage(
|
|||||||
return cryptography().isSignatureValid(bytesToSign, payload.signature ?: return false, pubkey)
|
return cryptography().isSignatureValid(bytesToSign, payload.signature ?: return false, pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val payloadBytesWithoutNonce: ByteArray by lazy {
|
||||||
|
val out = ByteArrayOutputStream()
|
||||||
|
writer.writeHeaderWithoutNonce(out)
|
||||||
|
payload.writer().write(out)
|
||||||
|
out.toByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val writer = Writer(this)
|
||||||
|
override fun writer(): StreamableWriter = writer
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: ObjectMessage
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
out.write(nonce ?: ByteArray(8))
|
out.write(item.nonce ?: ByteArray(8))
|
||||||
out.write(payloadBytesWithoutNonce)
|
out.write(item.payloadBytesWithoutNonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
buffer.put(nonce ?: ByteArray(8))
|
buffer.put(item.nonce ?: ByteArray(8))
|
||||||
buffer.put(payloadBytesWithoutNonce)
|
buffer.put(item.payloadBytesWithoutNonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeHeaderWithoutNonce(out: OutputStream) {
|
internal fun writeHeaderWithoutNonce(out: OutputStream) {
|
||||||
Encode.int64(expiresTime, out)
|
Encode.int64(item.expiresTime, out)
|
||||||
Encode.int32(type, out)
|
Encode.int32(item.type, out)
|
||||||
Encode.varInt(version, out)
|
Encode.varInt(item.version, out)
|
||||||
Encode.varInt(stream, out)
|
Encode.varInt(item.stream, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
val payloadBytesWithoutNonce: ByteArray by lazy {
|
|
||||||
val out = ByteArrayOutputStream()
|
|
||||||
writeHeaderWithoutNonce(out)
|
|
||||||
payload.write(out)
|
|
||||||
out.toByteArray()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
|
@ -260,102 +260,6 @@ class Plaintext private constructor(
|
|||||||
id = builder.id
|
id = builder.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fun write(out: OutputStream, includeSignature: Boolean) {
|
|
||||||
Encode.varInt(from.version, out)
|
|
||||||
Encode.varInt(from.stream, out)
|
|
||||||
from.pubkey?.apply {
|
|
||||||
Encode.int32(behaviorBitfield, out)
|
|
||||||
out.write(signingKey, 1, 64)
|
|
||||||
out.write(encryptionKey, 1, 64)
|
|
||||||
if (from.version >= 3) {
|
|
||||||
Encode.varInt(nonceTrialsPerByte, out)
|
|
||||||
Encode.varInt(extraBytes, out)
|
|
||||||
}
|
|
||||||
} ?: {
|
|
||||||
Encode.int32(0, out)
|
|
||||||
val empty = ByteArray(64)
|
|
||||||
out.write(empty)
|
|
||||||
out.write(empty)
|
|
||||||
if (from.version >= 3) {
|
|
||||||
Encode.varInt(0, out)
|
|
||||||
Encode.varInt(0, out)
|
|
||||||
}
|
|
||||||
}.invoke()
|
|
||||||
if (type == MSG) {
|
|
||||||
out.write(to?.ripe ?: throw IllegalStateException("No recipient set for message"))
|
|
||||||
}
|
|
||||||
Encode.varInt(encodingCode, out)
|
|
||||||
Encode.varInt(message.size, out)
|
|
||||||
out.write(message)
|
|
||||||
if (type == MSG) {
|
|
||||||
if (to?.has(Feature.DOES_ACK) ?: false) {
|
|
||||||
val ack = ByteArrayOutputStream()
|
|
||||||
ackMessage?.write(ack)
|
|
||||||
Encode.varBytes(ack.toByteArray(), out)
|
|
||||||
} else {
|
|
||||||
Encode.varInt(0, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (includeSignature) {
|
|
||||||
if (signature == null) {
|
|
||||||
Encode.varInt(0, out)
|
|
||||||
} else {
|
|
||||||
Encode.varBytes(signature!!, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun write(buffer: ByteBuffer, includeSignature: Boolean) {
|
|
||||||
Encode.varInt(from.version, buffer)
|
|
||||||
Encode.varInt(from.stream, buffer)
|
|
||||||
if (from.pubkey == null) {
|
|
||||||
Encode.int32(0, buffer)
|
|
||||||
val empty = ByteArray(64)
|
|
||||||
buffer.put(empty)
|
|
||||||
buffer.put(empty)
|
|
||||||
if (from.version >= 3) {
|
|
||||||
Encode.varInt(0, buffer)
|
|
||||||
Encode.varInt(0, buffer)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Encode.int32(from.pubkey!!.behaviorBitfield, buffer)
|
|
||||||
buffer.put(from.pubkey!!.signingKey, 1, 64)
|
|
||||||
buffer.put(from.pubkey!!.encryptionKey, 1, 64)
|
|
||||||
if (from.version >= 3) {
|
|
||||||
Encode.varInt(from.pubkey!!.nonceTrialsPerByte, buffer)
|
|
||||||
Encode.varInt(from.pubkey!!.extraBytes, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type == MSG) {
|
|
||||||
buffer.put(to!!.ripe)
|
|
||||||
}
|
|
||||||
Encode.varInt(encodingCode, buffer)
|
|
||||||
Encode.varBytes(message, buffer)
|
|
||||||
if (type == MSG) {
|
|
||||||
if (to!!.has(Feature.DOES_ACK) && ackMessage != null) {
|
|
||||||
Encode.varBytes(Encode.bytes(ackMessage!!), buffer)
|
|
||||||
} else {
|
|
||||||
Encode.varInt(0, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (includeSignature) {
|
|
||||||
val sig = signature
|
|
||||||
if (sig == null) {
|
|
||||||
Encode.varInt(0, buffer)
|
|
||||||
} else {
|
|
||||||
Encode.varBytes(sig, buffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
write(out, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
write(buffer, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateNextTry() {
|
fun updateNextTry() {
|
||||||
if (to != null) {
|
if (to != null) {
|
||||||
if (nextTry == null) {
|
if (nextTry == null) {
|
||||||
@ -484,6 +388,7 @@ class Plaintext private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class Encoding constructor(code: Long) {
|
enum class Encoding constructor(code: Long) {
|
||||||
|
|
||||||
IGNORE(0), TRIVIAL(1), SIMPLE(2), EXTENDED(3);
|
IGNORE(0), TRIVIAL(1), SIMPLE(2), EXTENDED(3);
|
||||||
|
|
||||||
var code: Long = 0
|
var code: Long = 0
|
||||||
@ -495,7 +400,8 @@ class Plaintext private constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic fun fromCode(code: Long): Encoding? {
|
@JvmStatic
|
||||||
|
fun fromCode(code: Long): Encoding? {
|
||||||
for (e in values()) {
|
for (e in values()) {
|
||||||
if (e.code == code) {
|
if (e.code == code) {
|
||||||
return e
|
return e
|
||||||
@ -503,12 +409,13 @@ class Plaintext private constructor(
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Status {
|
enum class Status {
|
||||||
|
|
||||||
DRAFT,
|
DRAFT,
|
||||||
// For sent messages
|
|
||||||
PUBKEY_REQUESTED,
|
PUBKEY_REQUESTED,
|
||||||
DOING_PROOF_OF_WORK,
|
DOING_PROOF_OF_WORK,
|
||||||
SENT,
|
SENT,
|
||||||
@ -517,9 +424,110 @@ class Plaintext private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
|
|
||||||
MSG, BROADCAST
|
MSG, BROADCAST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun writer(includeSignature: Boolean): StreamableWriter = Writer(this, includeSignature)
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: Plaintext,
|
||||||
|
private val includeSignature: Boolean = true
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
Encode.varInt(item.from.version, out)
|
||||||
|
Encode.varInt(item.from.stream, out)
|
||||||
|
item.from.pubkey?.apply {
|
||||||
|
Encode.int32(behaviorBitfield, out)
|
||||||
|
out.write(signingKey, 1, 64)
|
||||||
|
out.write(encryptionKey, 1, 64)
|
||||||
|
if (item.from.version >= 3) {
|
||||||
|
Encode.varInt(nonceTrialsPerByte, out)
|
||||||
|
Encode.varInt(extraBytes, out)
|
||||||
|
}
|
||||||
|
} ?: {
|
||||||
|
Encode.int32(0, out)
|
||||||
|
val empty = ByteArray(64)
|
||||||
|
out.write(empty)
|
||||||
|
out.write(empty)
|
||||||
|
if (item.from.version >= 3) {
|
||||||
|
Encode.varInt(0, out)
|
||||||
|
Encode.varInt(0, out)
|
||||||
|
}
|
||||||
|
}.invoke()
|
||||||
|
if (item.type == MSG) {
|
||||||
|
out.write(item.to?.ripe ?: throw IllegalStateException("No recipient set for message"))
|
||||||
|
}
|
||||||
|
Encode.varInt(item.encodingCode, out)
|
||||||
|
Encode.varInt(item.message.size, out)
|
||||||
|
out.write(item.message)
|
||||||
|
if (item.type == MSG) {
|
||||||
|
if (item.to?.has(Feature.DOES_ACK) == true) {
|
||||||
|
val ack = ByteArrayOutputStream()
|
||||||
|
item.ackMessage?.writer()?.write(ack)
|
||||||
|
Encode.varBytes(ack.toByteArray(), out)
|
||||||
|
} else {
|
||||||
|
Encode.varInt(0, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (includeSignature) {
|
||||||
|
val sig = item.signature
|
||||||
|
if (sig == null) {
|
||||||
|
Encode.varInt(0, out)
|
||||||
|
} else {
|
||||||
|
Encode.varBytes(sig, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
Encode.varInt(item.from.version, buffer)
|
||||||
|
Encode.varInt(item.from.stream, buffer)
|
||||||
|
if (item.from.pubkey == null) {
|
||||||
|
Encode.int32(0, buffer)
|
||||||
|
val empty = ByteArray(64)
|
||||||
|
buffer.put(empty)
|
||||||
|
buffer.put(empty)
|
||||||
|
if (item.from.version >= 3) {
|
||||||
|
Encode.varInt(0, buffer)
|
||||||
|
Encode.varInt(0, buffer)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Encode.int32(item.from.pubkey!!.behaviorBitfield, buffer)
|
||||||
|
buffer.put(item.from.pubkey!!.signingKey, 1, 64)
|
||||||
|
buffer.put(item.from.pubkey!!.encryptionKey, 1, 64)
|
||||||
|
if (item.from.version >= 3) {
|
||||||
|
Encode.varInt(item.from.pubkey!!.nonceTrialsPerByte, buffer)
|
||||||
|
Encode.varInt(item.from.pubkey!!.extraBytes, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.type == MSG) {
|
||||||
|
buffer.put(item.to!!.ripe)
|
||||||
|
}
|
||||||
|
Encode.varInt(item.encodingCode, buffer)
|
||||||
|
Encode.varBytes(item.message, buffer)
|
||||||
|
if (item.type == MSG) {
|
||||||
|
if (item.to!!.has(Feature.DOES_ACK) && item.ackMessage != null) {
|
||||||
|
Encode.varBytes(Encode.bytes(item.ackMessage!!), buffer)
|
||||||
|
} else {
|
||||||
|
Encode.varInt(0, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (includeSignature) {
|
||||||
|
val sig = item.signature
|
||||||
|
if (sig == null) {
|
||||||
|
Encode.varInt(0, buffer)
|
||||||
|
} else {
|
||||||
|
Encode.varBytes(sig, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class Builder(internal val type: Type) {
|
class Builder(internal val type: Type) {
|
||||||
internal var id: Any? = null
|
internal var id: Any? = null
|
||||||
internal var inventoryVector: InventoryVector? = null
|
internal var inventoryVector: InventoryVector? = null
|
||||||
@ -742,14 +750,16 @@ class Plaintext private constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic fun read(type: Type, `in`: InputStream): Plaintext {
|
@JvmStatic
|
||||||
|
fun read(type: Type, `in`: InputStream): Plaintext {
|
||||||
return readWithoutSignature(type, `in`)
|
return readWithoutSignature(type, `in`)
|
||||||
.signature(Decode.varBytes(`in`))
|
.signature(Decode.varBytes(`in`))
|
||||||
.received(UnixTime.now)
|
.received(UnixTime.now)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun readWithoutSignature(type: Type, `in`: InputStream): Plaintext.Builder {
|
@JvmStatic
|
||||||
|
fun readWithoutSignature(type: Type, `in`: InputStream): Plaintext.Builder {
|
||||||
val version = Decode.varInt(`in`)
|
val version = Decode.varInt(`in`)
|
||||||
return Builder(type)
|
return Builder(type)
|
||||||
.addressVersion(version)
|
.addressVersion(version)
|
||||||
|
@ -24,7 +24,27 @@ import java.nio.ByteBuffer
|
|||||||
* An object that can be written to an [OutputStream]
|
* An object that can be written to an [OutputStream]
|
||||||
*/
|
*/
|
||||||
interface Streamable : Serializable {
|
interface Streamable : Serializable {
|
||||||
fun write(out: OutputStream)
|
fun writer(): StreamableWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SignedStreamable : Streamable {
|
||||||
|
override fun writer(): SignedStreamableWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncryptedStreamable : SignedStreamable {
|
||||||
|
override fun writer(): EncryptedStreamableWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StreamableWriter: Serializable {
|
||||||
|
fun write(out: OutputStream)
|
||||||
fun write(buffer: ByteBuffer)
|
fun write(buffer: ByteBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SignedStreamableWriter : StreamableWriter {
|
||||||
|
fun writeBytesToSign(out: OutputStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncryptedStreamableWriter : SignedStreamableWriter {
|
||||||
|
fun writeUnencrypted(out: OutputStream)
|
||||||
|
fun writeUnencrypted(buffer: ByteBuffer)
|
||||||
|
}
|
||||||
|
@ -26,12 +26,12 @@ class VerAck : MessagePayload {
|
|||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.VERACK
|
override val command: MessagePayload.Command = MessagePayload.Command.VERACK
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
// 'verack' doesn't have any payload, so there is nothing to write
|
// 'verack' doesn't have any payload, so there is nothing to write
|
||||||
}
|
override fun writer(): StreamableWriter = EmptyWriter
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
internal object EmptyWriter : StreamableWriter {
|
||||||
// 'verack' doesn't have any payload, so there is nothing to write
|
override fun write(out: OutputStream) = Unit
|
||||||
|
override fun write(buffer: ByteBuffer) = Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -71,32 +71,36 @@ class Version constructor(
|
|||||||
val streams: LongArray = longArrayOf(1)
|
val streams: LongArray = longArrayOf(1)
|
||||||
) : MessagePayload {
|
) : MessagePayload {
|
||||||
|
|
||||||
fun provides(service: Service?): Boolean {
|
fun provides(service: Service?) = service?.isEnabled(services) == true
|
||||||
return service != null && service.isEnabled(services)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.VERSION
|
override val command: MessagePayload.Command = MessagePayload.Command.VERSION
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: Version
|
||||||
|
) : StreamableWriter {
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
Encode.int32(version, out)
|
Encode.int32(item.version, out)
|
||||||
Encode.int64(services, out)
|
Encode.int64(item.services, out)
|
||||||
Encode.int64(timestamp, out)
|
Encode.int64(item.timestamp, out)
|
||||||
addrRecv.write(out, true)
|
item.addrRecv.writer(true).write(out)
|
||||||
addrFrom.write(out, true)
|
item.addrFrom.writer(true).write(out)
|
||||||
Encode.int64(nonce, out)
|
Encode.int64(item.nonce, out)
|
||||||
Encode.varString(userAgent, out)
|
Encode.varString(item.userAgent, out)
|
||||||
Encode.varIntList(streams, out)
|
Encode.varIntList(item.streams, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
Encode.int32(version, buffer)
|
Encode.int32(item.version, buffer)
|
||||||
Encode.int64(services, buffer)
|
Encode.int64(item.services, buffer)
|
||||||
Encode.int64(timestamp, buffer)
|
Encode.int64(item.timestamp, buffer)
|
||||||
addrRecv.write(buffer, true)
|
item.addrRecv.writer(true).write(buffer)
|
||||||
addrFrom.write(buffer, true)
|
item.addrFrom.writer(true).write(buffer)
|
||||||
Encode.int64(nonce, buffer)
|
Encode.int64(item.nonce, buffer)
|
||||||
Encode.varString(userAgent, buffer)
|
Encode.varString(item.userAgent, buffer)
|
||||||
Encode.varIntList(streams, buffer)
|
Encode.varIntList(item.streams, buffer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
@ -187,9 +191,7 @@ class Version constructor(
|
|||||||
// TODO: NODE_SSL(2);
|
// TODO: NODE_SSL(2);
|
||||||
NODE_NETWORK(1);
|
NODE_NETWORK(1);
|
||||||
|
|
||||||
fun isEnabled(flag: Long): Boolean {
|
fun isEnabled(flag: Long) = (flag and this.flag) != 0L
|
||||||
return (flag and this.flag) != 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getServiceFlag(vararg services: Service): Long {
|
fun getServiceFlag(vararg services: Service): Long {
|
||||||
|
@ -29,7 +29,12 @@ import java.util.*
|
|||||||
* Users who are subscribed to the sending address will see the message appear in their inbox.
|
* Users who are subscribed to the sending address will see the message appear in their inbox.
|
||||||
* Broadcasts are version 4 or 5.
|
* Broadcasts are version 4 or 5.
|
||||||
*/
|
*/
|
||||||
abstract class Broadcast protected constructor(version: Long, override val stream: Long, protected var encrypted: CryptoBox?, override var plaintext: Plaintext?) : ObjectPayload(version), Encrypted, PlaintextHolder {
|
abstract class Broadcast protected constructor(
|
||||||
|
version: Long,
|
||||||
|
override val stream: Long,
|
||||||
|
protected var encrypted: CryptoBox?,
|
||||||
|
override var plaintext: Plaintext?
|
||||||
|
) : ObjectPayload(version), Encrypted, PlaintextHolder {
|
||||||
|
|
||||||
override val isSigned: Boolean = true
|
override val isSigned: Boolean = true
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.entity.valueobject.PrivateKey.Companion.PRIVATE_KEY_SIZE
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey.Companion.PRIVATE_KEY_SIZE
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
||||||
import ch.dissem.bitmessage.utils.*
|
import ch.dissem.bitmessage.utils.*
|
||||||
@ -108,16 +109,37 @@ class CryptoBox : Streamable {
|
|||||||
|
|
||||||
private fun calculateMac(key_m: ByteArray): ByteArray {
|
private fun calculateMac(key_m: ByteArray): ByteArray {
|
||||||
val macData = ByteArrayOutputStream()
|
val macData = ByteArrayOutputStream()
|
||||||
writeWithoutMAC(macData)
|
writer.writeWithoutMAC(macData)
|
||||||
return cryptography().mac(key_m, macData.toByteArray())
|
return cryptography().mac(key_m, macData.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeWithoutMAC(out: OutputStream) {
|
private val writer = Writer(this)
|
||||||
out.write(initializationVector)
|
override fun writer(): StreamableWriter = writer
|
||||||
Encode.int16(curveType, out)
|
|
||||||
writeCoordinateComponent(out, Points.getX(R))
|
private class Writer(
|
||||||
writeCoordinateComponent(out, Points.getY(R))
|
private val item: CryptoBox
|
||||||
out.write(encrypted)
|
) : StreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
writeWithoutMAC(out)
|
||||||
|
out.write(item.mac)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun writeWithoutMAC(out: OutputStream) {
|
||||||
|
out.write(item.initializationVector)
|
||||||
|
Encode.int16(item.curveType, out)
|
||||||
|
writeCoordinateComponent(out, Points.getX(item.R))
|
||||||
|
writeCoordinateComponent(out, Points.getY(item.R))
|
||||||
|
out.write(item.encrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
buffer.put(item.initializationVector)
|
||||||
|
Encode.int16(item.curveType, buffer)
|
||||||
|
writeCoordinateComponent(buffer, Points.getX(item.R))
|
||||||
|
writeCoordinateComponent(buffer, Points.getY(item.R))
|
||||||
|
buffer.put(item.encrypted)
|
||||||
|
buffer.put(item.mac)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeCoordinateComponent(out: OutputStream, x: ByteArray) {
|
private fun writeCoordinateComponent(out: OutputStream, x: ByteArray) {
|
||||||
@ -134,18 +156,6 @@ class CryptoBox : Streamable {
|
|||||||
buffer.put(x, offset, length)
|
buffer.put(x, offset, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
writeWithoutMAC(out)
|
|
||||||
out.write(mac)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
buffer.put(initializationVector)
|
|
||||||
Encode.int16(curveType, buffer)
|
|
||||||
writeCoordinateComponent(buffer, Points.getX(R))
|
|
||||||
writeCoordinateComponent(buffer, Points.getY(R))
|
|
||||||
buffer.put(encrypted)
|
|
||||||
buffer.put(mac)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
@ -187,15 +197,14 @@ class CryptoBox : Streamable {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(): CryptoBox {
|
fun build() = CryptoBox(this)
|
||||||
return CryptoBox(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG = LoggerFactory.getLogger(CryptoBox::class.java)
|
private val LOG = LoggerFactory.getLogger(CryptoBox::class.java)
|
||||||
|
|
||||||
@JvmStatic fun read(stream: InputStream, length: Int): CryptoBox {
|
@JvmStatic
|
||||||
|
fun read(stream: InputStream, length: Int): CryptoBox {
|
||||||
val counter = AccessCounter()
|
val counter = AccessCounter()
|
||||||
return Builder()
|
return Builder()
|
||||||
.IV(Decode.bytes(stream, 16, counter))
|
.IV(Decode.bytes(stream, 16, counter))
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Decode
|
import ch.dissem.bitmessage.utils.Decode
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@ -30,14 +31,6 @@ class GenericPayload(version: Long, override val stream: Long, val data: ByteArr
|
|||||||
|
|
||||||
override val type: ObjectType? = null
|
override val type: ObjectType? = null
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
out.write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
buffer.put(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is GenericPayload) return false
|
if (other !is GenericPayload) return false
|
||||||
@ -52,9 +45,27 @@ class GenericPayload(version: Long, override val stream: Long, val data: ByteArr
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
override fun writer(): SignedStreamableWriter = Writer(this)
|
||||||
@JvmStatic fun read(version: Long, stream: Long, `is`: InputStream, length: Int): GenericPayload {
|
|
||||||
return GenericPayload(version, stream, Decode.bytes(`is`, length))
|
private class Writer(
|
||||||
|
private val item: GenericPayload
|
||||||
|
) : SignedStreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
out.write(item.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
buffer.put(item.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeBytesToSign(out: OutputStream) = Unit // nothing to do
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun read(version: Long, stream: Long, `is`: InputStream, length: Int) =
|
||||||
|
GenericPayload(version, stream, Decode.bytes(`is`, length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Decode
|
import ch.dissem.bitmessage.utils.Decode
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@ -47,16 +48,27 @@ class GetPubkey : ObjectPayload {
|
|||||||
this.ripeTag = ripeOrTag
|
this.ripeTag = ripeOrTag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): SignedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: GetPubkey
|
||||||
|
) : SignedStreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
out.write(ripeTag)
|
out.write(item.ripeTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
buffer.put(ripeTag)
|
buffer.put(item.ripeTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeBytesToSign(out: OutputStream) = Unit // nothing to sign
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun read(`is`: InputStream, stream: Long, length: Int, version: Long): GetPubkey {
|
@JvmStatic
|
||||||
|
fun read(`is`: InputStream, stream: Long, length: Int, version: Long): GetPubkey {
|
||||||
return GetPubkey(version, stream, Decode.bytes(`is`, length))
|
return GetPubkey(version, stream, Decode.bytes(`is`, length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.Encrypted
|
import ch.dissem.bitmessage.entity.*
|
||||||
import ch.dissem.bitmessage.entity.Plaintext
|
|
||||||
import ch.dissem.bitmessage.entity.Plaintext.Type.MSG
|
import ch.dissem.bitmessage.entity.Plaintext.Type.MSG
|
||||||
import ch.dissem.bitmessage.entity.PlaintextHolder
|
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@ -51,10 +49,6 @@ class Msg : ObjectPayload, Encrypted, PlaintextHolder {
|
|||||||
|
|
||||||
override val isSigned: Boolean = true
|
override val isSigned: Boolean = true
|
||||||
|
|
||||||
override fun writeBytesToSign(out: OutputStream) {
|
|
||||||
plaintext?.write(out, false) ?: throw IllegalStateException("no plaintext data available")
|
|
||||||
}
|
|
||||||
|
|
||||||
override var signature: ByteArray?
|
override var signature: ByteArray?
|
||||||
get() = plaintext?.signature
|
get() = plaintext?.signature
|
||||||
set(signature) {
|
set(signature) {
|
||||||
@ -73,14 +67,6 @@ class Msg : ObjectPayload, Encrypted, PlaintextHolder {
|
|||||||
override val isDecrypted: Boolean
|
override val isDecrypted: Boolean
|
||||||
get() = plaintext != null
|
get() = plaintext != null
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
encrypted?.write(out) ?: throw IllegalStateException("Msg must be signed and encrypted before writing it.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
encrypted?.write(buffer) ?: throw IllegalStateException("Msg must be signed and encrypted before writing it.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is Msg) return false
|
if (other !is Msg) return false
|
||||||
@ -89,14 +75,35 @@ class Msg : ObjectPayload, Encrypted, PlaintextHolder {
|
|||||||
return stream == other.stream && (encrypted == other.encrypted || plaintext == other.plaintext)
|
return stream == other.stream && (encrypted == other.encrypted || plaintext == other.plaintext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode() = stream.toInt()
|
||||||
return stream.toInt()
|
|
||||||
|
override fun writer(): SignedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: Msg
|
||||||
|
) : SignedStreamableWriter {
|
||||||
|
|
||||||
|
val encryptedDataWriter = item.encrypted?.writer()
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
encryptedDataWriter?.write(out) ?: throw IllegalStateException("Msg must be signed and encrypted before writing it.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
encryptedDataWriter?.write(buffer) ?: throw IllegalStateException("Msg must be signed and encrypted before writing it.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeBytesToSign(out: OutputStream) {
|
||||||
|
item.plaintext?.writer(false)?.write(out) ?: throw IllegalStateException("no plaintext data available")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ACK_LENGTH = 32
|
val ACK_LENGTH = 32
|
||||||
|
|
||||||
@JvmStatic fun read(`in`: InputStream, stream: Long, length: Int): Msg {
|
@JvmStatic
|
||||||
|
fun read(`in`: InputStream, stream: Long, length: Int): Msg {
|
||||||
return Msg(stream, CryptoBox.read(`in`, length))
|
return Msg(stream, CryptoBox.read(`in`, length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,14 @@
|
|||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage
|
import ch.dissem.bitmessage.entity.ObjectMessage
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamable
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The payload of an 'object' command. This is shared by the network.
|
* The payload of an 'object' command. This is shared by the network.
|
||||||
*/
|
*/
|
||||||
abstract class ObjectPayload protected constructor(val version: Long) : Streamable {
|
abstract class ObjectPayload protected constructor(val version: Long) : SignedStreamable {
|
||||||
|
|
||||||
abstract val type: ObjectType?
|
abstract val type: ObjectType?
|
||||||
|
|
||||||
@ -31,10 +32,6 @@ abstract class ObjectPayload protected constructor(val version: Long) : Streamab
|
|||||||
|
|
||||||
open val isSigned: Boolean = false
|
open val isSigned: Boolean = false
|
||||||
|
|
||||||
open fun writeBytesToSign(out: OutputStream) {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the ECDSA signature which, as of protocol v3, covers the object header starting with the time,
|
* @return the ECDSA signature which, as of protocol v3, covers the object header starting with the time,
|
||||||
* * appended with the data described in this table down to the extra_bytes. Therefore, this must
|
* * appended with the data described in this table down to the extra_bytes. Therefore, this must
|
||||||
|
@ -18,6 +18,8 @@ package ch.dissem.bitmessage.entity.payload
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.InternalContext.Companion.NETWORK_EXTRA_BYTES
|
import ch.dissem.bitmessage.InternalContext.Companion.NETWORK_EXTRA_BYTES
|
||||||
import ch.dissem.bitmessage.InternalContext.Companion.NETWORK_NONCE_TRIALS_PER_BYTE
|
import ch.dissem.bitmessage.InternalContext.Companion.NETWORK_NONCE_TRIALS_PER_BYTE
|
||||||
|
import ch.dissem.bitmessage.entity.EncryptedStreamableWriter
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Singleton.cryptography
|
import ch.dissem.bitmessage.utils.Singleton.cryptography
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@ -42,13 +44,7 @@ abstract class Pubkey protected constructor(version: Long) : ObjectPayload(versi
|
|||||||
|
|
||||||
open val extraBytes: Long = NETWORK_EXTRA_BYTES
|
open val extraBytes: Long = NETWORK_EXTRA_BYTES
|
||||||
|
|
||||||
open fun writeUnencrypted(out: OutputStream) {
|
abstract override fun writer(): EncryptedStreamableWriter
|
||||||
write(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun writeUnencrypted(buffer: ByteBuffer) {
|
|
||||||
write(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bits 0 through 29 are yet undefined
|
* Bits 0 through 29 are yet undefined
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.EncryptedStreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Decode
|
import ch.dissem.bitmessage.utils.Decode
|
||||||
import ch.dissem.bitmessage.utils.Encode
|
import ch.dissem.bitmessage.utils.Encode
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -25,21 +26,47 @@ import java.nio.ByteBuffer
|
|||||||
/**
|
/**
|
||||||
* A version 2 public key.
|
* A version 2 public key.
|
||||||
*/
|
*/
|
||||||
open class V2Pubkey constructor(version: Long, override val stream: Long, override val behaviorBitfield: Int, signingKey: ByteArray, encryptionKey: ByteArray) : Pubkey(version) {
|
open class V2Pubkey constructor(
|
||||||
|
version: Long,
|
||||||
|
override val stream: Long,
|
||||||
|
override val behaviorBitfield: Int,
|
||||||
|
signingKey: ByteArray,
|
||||||
|
encryptionKey: ByteArray
|
||||||
|
) : Pubkey(version) {
|
||||||
|
|
||||||
override val signingKey: ByteArray = if (signingKey.size == 64) add0x04(signingKey) else signingKey
|
override val signingKey: ByteArray = if (signingKey.size == 64) add0x04(signingKey) else signingKey
|
||||||
override val encryptionKey: ByteArray = if (encryptionKey.size == 64) add0x04(encryptionKey) else encryptionKey
|
override val encryptionKey: ByteArray = if (encryptionKey.size == 64) add0x04(encryptionKey) else encryptionKey
|
||||||
|
|
||||||
|
override fun writer(): EncryptedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
protected open class Writer(
|
||||||
|
private val item: V2Pubkey
|
||||||
|
) : EncryptedStreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
Encode.int32(behaviorBitfield, out)
|
Encode.int32(item.behaviorBitfield, out)
|
||||||
out.write(signingKey, 1, 64)
|
out.write(item.signingKey, 1, 64)
|
||||||
out.write(encryptionKey, 1, 64)
|
out.write(item.encryptionKey, 1, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
Encode.int32(behaviorBitfield, buffer)
|
Encode.int32(item.behaviorBitfield, buffer)
|
||||||
buffer.put(signingKey, 1, 64)
|
buffer.put(item.signingKey, 1, 64)
|
||||||
buffer.put(encryptionKey, 1, 64)
|
buffer.put(item.encryptionKey, 1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeBytesToSign(out: OutputStream) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeUnencrypted(out: OutputStream) {
|
||||||
|
write(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeUnencrypted(buffer: ByteBuffer) {
|
||||||
|
write(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload
|
package ch.dissem.bitmessage.entity.payload
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.EncryptedStreamableWriter
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamableWriter
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Decode
|
import ch.dissem.bitmessage.utils.Decode
|
||||||
import ch.dissem.bitmessage.utils.Encode
|
import ch.dissem.bitmessage.utils.Encode
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -34,32 +37,8 @@ class V3Pubkey protected constructor(
|
|||||||
override var signature: ByteArray? = null
|
override var signature: ByteArray? = null
|
||||||
) : V2Pubkey(version, stream, behaviorBitfield, signingKey, encryptionKey) {
|
) : V2Pubkey(version, stream, behaviorBitfield, signingKey, encryptionKey) {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
writeBytesToSign(out)
|
|
||||||
Encode.varBytes(
|
|
||||||
signature ?: throw IllegalStateException("signature not available"),
|
|
||||||
out
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
super.write(buffer)
|
|
||||||
Encode.varInt(nonceTrialsPerByte, buffer)
|
|
||||||
Encode.varInt(extraBytes, buffer)
|
|
||||||
Encode.varBytes(
|
|
||||||
signature ?: throw IllegalStateException("signature not available"),
|
|
||||||
buffer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val isSigned: Boolean = true
|
override val isSigned: Boolean = true
|
||||||
|
|
||||||
override fun writeBytesToSign(out: OutputStream) {
|
|
||||||
super.write(out)
|
|
||||||
Encode.varInt(nonceTrialsPerByte, out)
|
|
||||||
Encode.varInt(extraBytes, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is V3Pubkey) return false
|
if (other !is V3Pubkey) return false
|
||||||
@ -75,6 +54,37 @@ class V3Pubkey protected constructor(
|
|||||||
return Objects.hash(nonceTrialsPerByte, extraBytes)
|
return Objects.hash(nonceTrialsPerByte, extraBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): EncryptedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
protected open class Writer(
|
||||||
|
private val item: V3Pubkey
|
||||||
|
) : V2Pubkey.Writer(item) {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
writeBytesToSign(out)
|
||||||
|
Encode.varBytes(
|
||||||
|
item.signature ?: throw IllegalStateException("signature not available"),
|
||||||
|
out
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
super.write(buffer)
|
||||||
|
Encode.varInt(item.nonceTrialsPerByte, buffer)
|
||||||
|
Encode.varInt(item.extraBytes, buffer)
|
||||||
|
Encode.varBytes(
|
||||||
|
item.signature ?: throw IllegalStateException("signature not available"),
|
||||||
|
buffer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeBytesToSign(out: OutputStream) {
|
||||||
|
super.write(out)
|
||||||
|
Encode.varInt(item.nonceTrialsPerByte, out)
|
||||||
|
Encode.varInt(item.extraBytes, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
private var streamNumber: Long = 0
|
private var streamNumber: Long = 0
|
||||||
private var behaviorBitfield: Int = 0
|
private var behaviorBitfield: Int = 0
|
||||||
|
@ -18,7 +18,7 @@ package ch.dissem.bitmessage.entity.payload
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
import ch.dissem.bitmessage.entity.Plaintext
|
import ch.dissem.bitmessage.entity.Plaintext
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamableWriter
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@ -38,21 +38,28 @@ open class V4Broadcast : Broadcast {
|
|||||||
throw IllegalArgumentException("Address version 3 or older expected, but was " + senderAddress.version)
|
throw IllegalArgumentException("Address version 3 or older expected, but was " + senderAddress.version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): SignedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
protected open class Writer(
|
||||||
|
private val item: V4Broadcast
|
||||||
|
) : SignedStreamableWriter {
|
||||||
|
|
||||||
override fun writeBytesToSign(out: OutputStream) {
|
override fun writeBytesToSign(out: OutputStream) {
|
||||||
plaintext?.write(out, false) ?: throw IllegalStateException("no plaintext data available")
|
item.plaintext?.writer(false)?.write(out) ?: throw IllegalStateException("no plaintext data available")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
encrypted?.write(out) ?: throw IllegalStateException("broadcast not encrypted")
|
item.encrypted?.writer()?.write(out) ?: throw IllegalStateException("broadcast not encrypted")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
encrypted?.write(buffer) ?: throw IllegalStateException("broadcast not encrypted")
|
item.encrypted?.writer()?.write(buffer) ?: throw IllegalStateException("broadcast not encrypted")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun read(`in`: InputStream, stream: Long, length: Int): V4Broadcast {
|
@JvmStatic
|
||||||
|
fun read(`in`: InputStream, stream: Long, length: Int): V4Broadcast {
|
||||||
return V4Broadcast(4, stream, CryptoBox.read(`in`, length), null)
|
return V4Broadcast(4, stream, CryptoBox.read(`in`, length), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity.payload
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
import ch.dissem.bitmessage.entity.Encrypted
|
import ch.dissem.bitmessage.entity.Encrypted
|
||||||
|
import ch.dissem.bitmessage.entity.EncryptedStreamableWriter
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
||||||
import ch.dissem.bitmessage.utils.Decode
|
import ch.dissem.bitmessage.utils.Decode
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -63,29 +64,6 @@ class V4Pubkey : Pubkey, Encrypted {
|
|||||||
override val isDecrypted: Boolean
|
override val isDecrypted: Boolean
|
||||||
get() = decrypted != null
|
get() = decrypted != null
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
out.write(tag)
|
|
||||||
encrypted?.write(out) ?: throw IllegalStateException("pubkey is encrypted")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
buffer.put(tag)
|
|
||||||
encrypted?.write(buffer) ?: throw IllegalStateException("pubkey is encrypted")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun writeUnencrypted(out: OutputStream) {
|
|
||||||
decrypted?.write(out) ?: throw IllegalStateException("pubkey is encrypted")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun writeUnencrypted(buffer: ByteBuffer) {
|
|
||||||
decrypted?.write(buffer) ?: throw IllegalStateException("pubkey is encrypted")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun writeBytesToSign(out: OutputStream) {
|
|
||||||
out.write(tag)
|
|
||||||
decrypted?.writeBytesToSign(out) ?: throw IllegalStateException("pubkey is encrypted")
|
|
||||||
}
|
|
||||||
|
|
||||||
override val signingKey: ByteArray
|
override val signingKey: ByteArray
|
||||||
get() = decrypted?.signingKey ?: throw IllegalStateException("pubkey is encrypted")
|
get() = decrypted?.signingKey ?: throw IllegalStateException("pubkey is encrypted")
|
||||||
|
|
||||||
@ -126,8 +104,40 @@ class V4Pubkey : Pubkey, Encrypted {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): EncryptedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
val item: V4Pubkey
|
||||||
|
) : EncryptedStreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
out.write(item.tag)
|
||||||
|
item.encrypted?.writer()?.write(out) ?: throw IllegalStateException("pubkey is encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
buffer.put(item.tag)
|
||||||
|
item.encrypted?.writer()?.write(buffer) ?: throw IllegalStateException("pubkey is encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeUnencrypted(out: OutputStream) {
|
||||||
|
item.decrypted?.writer()?.write(out) ?: throw IllegalStateException("pubkey is encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeUnencrypted(buffer: ByteBuffer) {
|
||||||
|
item.decrypted?.writer()?.write(buffer) ?: throw IllegalStateException("pubkey is encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeBytesToSign(out: OutputStream) {
|
||||||
|
out.write(item.tag)
|
||||||
|
item.decrypted?.writer()?.writeBytesToSign(out) ?: throw IllegalStateException("pubkey is encrypted")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun read(`in`: InputStream, stream: Long, length: Int, encrypted: Boolean): V4Pubkey {
|
@JvmStatic
|
||||||
|
fun read(`in`: InputStream, stream: Long, length: Int, encrypted: Boolean): V4Pubkey {
|
||||||
if (encrypted)
|
if (encrypted)
|
||||||
return V4Pubkey(stream,
|
return V4Pubkey(stream,
|
||||||
Decode.bytes(`in`, 32),
|
Decode.bytes(`in`, 32),
|
||||||
|
@ -18,6 +18,7 @@ package ch.dissem.bitmessage.entity.payload
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
import ch.dissem.bitmessage.entity.Plaintext
|
import ch.dissem.bitmessage.entity.Plaintext
|
||||||
|
import ch.dissem.bitmessage.entity.SignedStreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Decode
|
import ch.dissem.bitmessage.utils.Decode
|
||||||
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -40,18 +41,27 @@ class V5Broadcast : V4Broadcast {
|
|||||||
this.tag = senderAddress.tag ?: throw IllegalStateException("version 4 address without tag")
|
this.tag = senderAddress.tag ?: throw IllegalStateException("version 4 address without tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): SignedStreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: V5Broadcast
|
||||||
|
) : V4Broadcast.Writer(item) {
|
||||||
|
|
||||||
override fun writeBytesToSign(out: OutputStream) {
|
override fun writeBytesToSign(out: OutputStream) {
|
||||||
out.write(tag)
|
out.write(item.tag)
|
||||||
super.writeBytesToSign(out)
|
super.writeBytesToSign(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
out.write(tag)
|
out.write(item.tag)
|
||||||
super.write(out)
|
super.write(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun read(`is`: InputStream, stream: Long, length: Int): V5Broadcast {
|
@JvmStatic
|
||||||
|
fun read(`is`: InputStream, stream: Long, length: Int): V5Broadcast {
|
||||||
return V5Broadcast(stream, Decode.bytes(`is`, 32), CryptoBox.read(`is`, length - 32))
|
return V5Broadcast(stream, Decode.bytes(`is`, 32), CryptoBox.read(`is`, length - 32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.entity.valueobject
|
package ch.dissem.bitmessage.entity.valueobject
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.utils.Strings
|
import ch.dissem.bitmessage.utils.Strings
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
@ -39,20 +40,29 @@ data class InventoryVector constructor(
|
|||||||
return Arrays.hashCode(hash)
|
return Arrays.hashCode(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
out.write(hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
buffer.put(hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return Strings.hex(hash)
|
return Strings.hex(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: InventoryVector
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
out.write(item.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
buffer.put(item.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun fromHash(hash: ByteArray?): InventoryVector? {
|
@JvmStatic
|
||||||
|
fun fromHash(hash: ByteArray?): InventoryVector? {
|
||||||
return InventoryVector(
|
return InventoryVector(
|
||||||
hash ?: return null
|
hash ?: return null
|
||||||
)
|
)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.entity.valueobject
|
package ch.dissem.bitmessage.entity.valueobject
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.entity.Version
|
import ch.dissem.bitmessage.entity.Version
|
||||||
import ch.dissem.bitmessage.utils.Encode
|
import ch.dissem.bitmessage.utils.Encode
|
||||||
import ch.dissem.bitmessage.utils.UnixTime
|
import ch.dissem.bitmessage.utils.UnixTime
|
||||||
@ -77,9 +78,7 @@ data class NetworkAddress(
|
|||||||
|
|
||||||
fun provides(service: Version.Service?): Boolean = service?.isEnabled(services) ?: false
|
fun provides(service: Version.Service?): Boolean = service?.isEnabled(services) ?: false
|
||||||
|
|
||||||
fun toInetAddress(): InetAddress {
|
fun toInetAddress() = InetAddress.getByAddress(IPv6)
|
||||||
return InetAddress.getByAddress(IPv6)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
@ -98,32 +97,40 @@ data class NetworkAddress(
|
|||||||
return "[" + toInetAddress() + "]:" + port
|
return "[" + toInetAddress() + "]:" + port
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
fun writer(light: Boolean): StreamableWriter = Writer(
|
||||||
write(out, false)
|
item = this,
|
||||||
}
|
light = light
|
||||||
|
)
|
||||||
|
|
||||||
fun write(out: OutputStream, light: Boolean) {
|
override fun writer(): StreamableWriter = Writer(
|
||||||
|
item = this
|
||||||
|
)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: NetworkAddress,
|
||||||
|
private val light: Boolean = false
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
if (!light) {
|
if (!light) {
|
||||||
Encode.int64(time, out)
|
Encode.int64(item.time, out)
|
||||||
Encode.int32(stream, out)
|
Encode.int32(item.stream, out)
|
||||||
}
|
}
|
||||||
Encode.int64(services, out)
|
Encode.int64(item.services, out)
|
||||||
out.write(IPv6)
|
out.write(item.IPv6)
|
||||||
Encode.int16(port, out)
|
Encode.int16(item.port, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
write(buffer, false)
|
if (!light) {
|
||||||
|
Encode.int64(item.time, buffer)
|
||||||
|
Encode.int32(item.stream, buffer)
|
||||||
|
}
|
||||||
|
Encode.int64(item.services, buffer)
|
||||||
|
buffer.put(item.IPv6)
|
||||||
|
Encode.int16(item.port, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun write(buffer: ByteBuffer, light: Boolean) {
|
|
||||||
if (!light) {
|
|
||||||
Encode.int64(time, buffer)
|
|
||||||
Encode.int32(stream, buffer)
|
|
||||||
}
|
|
||||||
Encode.int64(services, buffer)
|
|
||||||
buffer.put(IPv6)
|
|
||||||
Encode.int16(port, buffer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
@ -194,6 +201,7 @@ data class NetworkAddress(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val ANY = NetworkAddress(time = 0, stream = 0, services = 0, IPv6 = ByteArray(16), port = 0)
|
@JvmField
|
||||||
|
val ANY = NetworkAddress(time = 0, stream = 0, services = 0, IPv6 = ByteArray(16), port = 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package ch.dissem.bitmessage.entity.valueobject
|
|||||||
import ch.dissem.bitmessage.InternalContext
|
import ch.dissem.bitmessage.InternalContext
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey
|
import ch.dissem.bitmessage.entity.payload.Pubkey
|
||||||
import ch.dissem.bitmessage.exception.ApplicationException
|
import ch.dissem.bitmessage.exception.ApplicationException
|
||||||
import ch.dissem.bitmessage.factory.Factory
|
import ch.dissem.bitmessage.factory.Factory
|
||||||
@ -66,7 +67,52 @@ data class PrivateKey(
|
|||||||
builder.nonceTrialsPerByte, builder.extraBytes, *builder.features)
|
builder.nonceTrialsPerByte, builder.extraBytes, *builder.features)
|
||||||
)
|
)
|
||||||
|
|
||||||
private class Builder internal constructor(internal val version: Long, internal val stream: Long, internal val shorter: Boolean) {
|
override fun equals(other: Any?) = other is PrivateKey
|
||||||
|
&& Arrays.equals(privateEncryptionKey, other.privateEncryptionKey)
|
||||||
|
&& Arrays.equals(privateSigningKey, other.privateSigningKey)
|
||||||
|
&& pubkey == other.pubkey
|
||||||
|
|
||||||
|
override fun hashCode() = pubkey.hashCode()
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: PrivateKey
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
|
override fun write(out: OutputStream) {
|
||||||
|
Encode.varInt(item.pubkey.version, out)
|
||||||
|
Encode.varInt(item.pubkey.stream, out)
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
item.pubkey.writer().writeUnencrypted(baos)
|
||||||
|
Encode.varInt(baos.size(), out)
|
||||||
|
out.write(baos.toByteArray())
|
||||||
|
Encode.varBytes(item.privateSigningKey, out)
|
||||||
|
Encode.varBytes(item.privateEncryptionKey, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buffer: ByteBuffer) {
|
||||||
|
Encode.varInt(item.pubkey.version, buffer)
|
||||||
|
Encode.varInt(item.pubkey.stream, buffer)
|
||||||
|
try {
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
item.pubkey.writer().writeUnencrypted(baos)
|
||||||
|
Encode.varBytes(baos.toByteArray(), buffer)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw ApplicationException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
Encode.varBytes(item.privateSigningKey, buffer)
|
||||||
|
Encode.varBytes(item.privateEncryptionKey, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Builder internal constructor(
|
||||||
|
internal val version: Long,
|
||||||
|
internal val stream: Long,
|
||||||
|
internal val shorter: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
internal var seed: ByteArray? = null
|
internal var seed: ByteArray? = null
|
||||||
internal var nextNonce: Long = 0
|
internal var nextNonce: Long = 0
|
||||||
@ -129,44 +175,12 @@ data class PrivateKey(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
|
||||||
Encode.varInt(pubkey.version, out)
|
|
||||||
Encode.varInt(pubkey.stream, out)
|
|
||||||
val baos = ByteArrayOutputStream()
|
|
||||||
pubkey.writeUnencrypted(baos)
|
|
||||||
Encode.varInt(baos.size(), out)
|
|
||||||
out.write(baos.toByteArray())
|
|
||||||
Encode.varBytes(privateSigningKey, out)
|
|
||||||
Encode.varBytes(privateEncryptionKey, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
|
||||||
Encode.varInt(pubkey.version, buffer)
|
|
||||||
Encode.varInt(pubkey.stream, buffer)
|
|
||||||
try {
|
|
||||||
val baos = ByteArrayOutputStream()
|
|
||||||
pubkey.writeUnencrypted(baos)
|
|
||||||
Encode.varBytes(baos.toByteArray(), buffer)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
throw ApplicationException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
Encode.varBytes(privateSigningKey, buffer)
|
|
||||||
Encode.varBytes(privateEncryptionKey, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is PrivateKey
|
|
||||||
&& Arrays.equals(privateEncryptionKey, other.privateEncryptionKey)
|
|
||||||
&& Arrays.equals(privateSigningKey, other.privateSigningKey)
|
|
||||||
&& pubkey == other.pubkey
|
|
||||||
|
|
||||||
override fun hashCode() = pubkey.hashCode()
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val PRIVATE_KEY_SIZE = 32
|
@JvmField
|
||||||
|
val PRIVATE_KEY_SIZE = 32
|
||||||
|
|
||||||
@JvmStatic fun deterministic(passphrase: String, numberOfAddresses: Int, version: Long, stream: Long, shorter: Boolean): List<PrivateKey> {
|
@JvmStatic
|
||||||
|
fun deterministic(passphrase: String, numberOfAddresses: Int, version: Long, stream: Long, shorter: Boolean): List<PrivateKey> {
|
||||||
val result = ArrayList<PrivateKey>(numberOfAddresses)
|
val result = ArrayList<PrivateKey>(numberOfAddresses)
|
||||||
val builder = Builder(version, stream, shorter).seed(passphrase)
|
val builder = Builder(version, stream, shorter).seed(passphrase)
|
||||||
for (i in 0..numberOfAddresses - 1) {
|
for (i in 0..numberOfAddresses - 1) {
|
||||||
@ -176,7 +190,8 @@ data class PrivateKey(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun read(`is`: InputStream): PrivateKey {
|
@JvmStatic
|
||||||
|
fun read(`is`: InputStream): PrivateKey {
|
||||||
val version = Decode.varInt(`is`).toInt()
|
val version = Decode.varInt(`is`).toInt()
|
||||||
val stream = Decode.varInt(`is`)
|
val stream = Decode.varInt(`is`)
|
||||||
val len = Decode.varInt(`is`).toInt()
|
val len = Decode.varInt(`is`).toInt()
|
||||||
|
@ -45,25 +45,25 @@ data class Message constructor(
|
|||||||
|
|
||||||
override fun pack(): MPMap<MPString, MPType<*>> {
|
override fun pack(): MPMap<MPString, MPType<*>> {
|
||||||
val result = MPMap<MPString, MPType<*>>()
|
val result = MPMap<MPString, MPType<*>>()
|
||||||
result.put(mp(""), mp(TYPE))
|
result.put("".mp, TYPE.mp)
|
||||||
result.put(mp("subject"), mp(subject))
|
result.put("subject".mp, subject.mp)
|
||||||
result.put(mp("body"), mp(body))
|
result.put("body".mp, body.mp)
|
||||||
|
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
val items = MPArray<MPMap<MPString, MPType<*>>>()
|
val items = MPArray<MPMap<MPString, MPType<*>>>()
|
||||||
result.put(mp("files"), items)
|
result.put("files".mp, items)
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
val item = MPMap<MPString, MPType<*>>()
|
val item = MPMap<MPString, MPType<*>>()
|
||||||
item.put(mp("name"), mp(file.name))
|
item.put("name".mp, file.name.mp)
|
||||||
item.put(mp("data"), mp(*file.data))
|
item.put("data".mp, file.data.mp)
|
||||||
item.put(mp("type"), mp(file.type))
|
item.put("type".mp, file.type.mp)
|
||||||
item.put(mp("disposition"), mp(file.disposition.name))
|
item.put("disposition".mp, file.disposition.name.mp)
|
||||||
items.add(item)
|
items.add(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!parents.isEmpty()) {
|
if (!parents.isEmpty()) {
|
||||||
val items = MPArray<MPBinary>()
|
val items = MPArray<MPBinary>()
|
||||||
result.put(mp("parents"), items)
|
result.put("parents".mp, items)
|
||||||
for ((hash) in parents) {
|
for ((hash) in parents) {
|
||||||
items.add(mp(*hash))
|
items.add(mp(*hash))
|
||||||
}
|
}
|
||||||
@ -139,26 +139,26 @@ data class Message constructor(
|
|||||||
override val type: String = TYPE
|
override val type: String = TYPE
|
||||||
|
|
||||||
override fun unpack(map: MPMap<MPString, MPType<*>>): Message {
|
override fun unpack(map: MPMap<MPString, MPType<*>>): Message {
|
||||||
val subject = str(map[mp("subject")]) ?: ""
|
val subject = str(map["subject".mp]) ?: ""
|
||||||
val body = str(map[mp("body")]) ?: ""
|
val body = str(map["body".mp]) ?: ""
|
||||||
val parents = LinkedList<InventoryVector>()
|
val parents = LinkedList<InventoryVector>()
|
||||||
val files = LinkedList<Attachment>()
|
val files = LinkedList<Attachment>()
|
||||||
val mpParents = map[mp("parents")] as? MPArray<*>
|
val mpParents = map["parents".mp] as? MPArray<*>
|
||||||
for (parent in mpParents ?: emptyList<MPArray<MPBinary>>()) {
|
for (parent in mpParents ?: emptyList<MPArray<MPBinary>>()) {
|
||||||
parents.add(InventoryVector.fromHash(
|
parents.add(InventoryVector.fromHash(
|
||||||
(parent as? MPBinary)?.value ?: continue
|
(parent as? MPBinary)?.value ?: continue
|
||||||
) ?: continue)
|
) ?: continue)
|
||||||
}
|
}
|
||||||
val mpFiles = map[mp("files")] as? MPArray<*>
|
val mpFiles = map["files".mp] as? MPArray<*>
|
||||||
for (item in mpFiles ?: emptyList<Any>()) {
|
for (item in mpFiles ?: emptyList<Any>()) {
|
||||||
if (item is MPMap<*, *>) {
|
if (item is MPMap<*, *>) {
|
||||||
val b = Attachment.Builder()
|
val b = Attachment.Builder()
|
||||||
b.name(str(item[mp("name")])!!)
|
b.name(str(item["name".mp])!!)
|
||||||
b.data(
|
b.data(
|
||||||
bin(item[mp("data")] ?: continue) ?: continue
|
bin(item["data".mp] ?: continue) ?: continue
|
||||||
)
|
)
|
||||||
b.type(str(item[mp("type")])!!)
|
b.type(str(item["type".mp])!!)
|
||||||
val disposition = str(item[mp("disposition")])
|
val disposition = str(item["disposition".mp])
|
||||||
if ("inline" == disposition) {
|
if ("inline" == disposition) {
|
||||||
b.inline()
|
b.inline()
|
||||||
} else if ("attachment" == disposition) {
|
} else if ("attachment" == disposition) {
|
||||||
|
@ -35,9 +35,9 @@ data class Vote constructor(val msgId: InventoryVector, val vote: String) : Exte
|
|||||||
|
|
||||||
override fun pack(): MPMap<MPString, MPType<*>> {
|
override fun pack(): MPMap<MPString, MPType<*>> {
|
||||||
val result = MPMap<MPString, MPType<*>>()
|
val result = MPMap<MPString, MPType<*>>()
|
||||||
result.put(mp(""), mp(TYPE))
|
result.put("".mp, TYPE.mp)
|
||||||
result.put(mp("msgId"), mp(*msgId.hash))
|
result.put("msgId".mp, msgId.hash.mp)
|
||||||
result.put(mp("vote"), mp(vote))
|
result.put("vote".mp, vote.mp)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,13 +77,14 @@ data class Vote constructor(val msgId: InventoryVector, val vote: String) : Exte
|
|||||||
get() = TYPE
|
get() = TYPE
|
||||||
|
|
||||||
override fun unpack(map: MPMap<MPString, MPType<*>>): Vote {
|
override fun unpack(map: MPMap<MPString, MPType<*>>): Vote {
|
||||||
val msgId = InventoryVector.fromHash((map[mp("msgId")] as? MPBinary)?.value) ?: throw IllegalArgumentException("data doesn't contain proper msgId")
|
val msgId = InventoryVector.fromHash((map["msgId".mp] as? MPBinary)?.value) ?: throw IllegalArgumentException("data doesn't contain proper msgId")
|
||||||
val vote = str(map[mp("vote")]) ?: throw IllegalArgumentException("no vote given")
|
val vote = str(map["vote".mp]) ?: throw IllegalArgumentException("no vote given")
|
||||||
return Vote(msgId, vote)
|
return Vote(msgId, vote)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val TYPE = "vote"
|
@JvmField
|
||||||
|
val TYPE = "vote"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,8 @@ object ExtendedEncodingFactory {
|
|||||||
fun unzip(zippedData: ByteArray): ExtendedEncoding? {
|
fun unzip(zippedData: ByteArray): ExtendedEncoding? {
|
||||||
try {
|
try {
|
||||||
InflaterInputStream(ByteArrayInputStream(zippedData)).use { unzipper ->
|
InflaterInputStream(ByteArrayInputStream(zippedData)).use { unzipper ->
|
||||||
val reader = Reader.getInstance()
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val map = reader.read(unzipper) as MPMap<MPString, MPType<*>>
|
val map = Reader.read(unzipper) as MPMap<MPString, MPType<*>>
|
||||||
val messageType = map[KEY_MESSAGE_TYPE]
|
val messageType = map[KEY_MESSAGE_TYPE]
|
||||||
if (messageType == null) {
|
if (messageType == null) {
|
||||||
LOG.error("Missing message type")
|
LOG.error("Missing message type")
|
||||||
|
@ -31,4 +31,13 @@ interface NodeRegistry {
|
|||||||
fun getKnownAddresses(limit: Int, vararg streams: Long): List<NetworkAddress>
|
fun getKnownAddresses(limit: Int, vararg streams: Long): List<NetworkAddress>
|
||||||
|
|
||||||
fun offerAddresses(nodes: List<NetworkAddress>)
|
fun offerAddresses(nodes: List<NetworkAddress>)
|
||||||
|
|
||||||
|
fun update(node: NetworkAddress)
|
||||||
|
|
||||||
|
fun remove(node: NetworkAddress)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove stale nodes
|
||||||
|
*/
|
||||||
|
fun cleanup()
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ object DebugUtils {
|
|||||||
try {
|
try {
|
||||||
val f = File(System.getProperty("user.home") + "/jabit.error/" + objectMessage.inventoryVector + ".inv")
|
val f = File(System.getProperty("user.home") + "/jabit.error/" + objectMessage.inventoryVector + ".inv")
|
||||||
f.createNewFile()
|
f.createNewFile()
|
||||||
objectMessage.write(FileOutputStream(f))
|
objectMessage.writer().write(FileOutputStream(f))
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
LOG.debug(e.message, e)
|
LOG.debug(e.message, e)
|
||||||
}
|
}
|
||||||
|
@ -26,22 +26,27 @@ import java.nio.ByteBuffer
|
|||||||
* https://bitmessage.org/wiki/Protocol_specification#Common_structures
|
* https://bitmessage.org/wiki/Protocol_specification#Common_structures
|
||||||
*/
|
*/
|
||||||
object Encode {
|
object Encode {
|
||||||
@JvmStatic fun varIntList(values: LongArray, stream: OutputStream) {
|
@JvmStatic
|
||||||
|
fun varIntList(values: LongArray, stream: OutputStream) {
|
||||||
varInt(values.size, stream)
|
varInt(values.size, stream)
|
||||||
for (value in values) {
|
for (value in values) {
|
||||||
varInt(value, stream)
|
varInt(value, stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varIntList(values: LongArray, buffer: ByteBuffer) {
|
@JvmStatic
|
||||||
|
fun varIntList(values: LongArray, buffer: ByteBuffer) {
|
||||||
varInt(values.size, buffer)
|
varInt(values.size, buffer)
|
||||||
for (value in values) {
|
for (value in values) {
|
||||||
varInt(value, buffer)
|
varInt(value, buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varInt(value: Int, buffer: ByteBuffer) = varInt(value.toLong(), buffer)
|
@JvmStatic
|
||||||
@JvmStatic fun varInt(value: Long, buffer: ByteBuffer) {
|
fun varInt(value: Int, buffer: ByteBuffer) = varInt(value.toLong(), buffer)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun varInt(value: Long, buffer: ByteBuffer) {
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
// This is due to the fact that Java doesn't really support unsigned values.
|
// This is due to the fact that Java doesn't really support unsigned values.
|
||||||
// Please be aware that this might be an error due to a smaller negative value being cast to long.
|
// Please be aware that this might be an error due to a smaller negative value being cast to long.
|
||||||
@ -63,16 +68,24 @@ object Encode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varInt(value: Int) = varInt(value.toLong())
|
@JvmStatic
|
||||||
@JvmStatic fun varInt(value: Long): ByteArray {
|
fun varInt(value: Int) = varInt(value.toLong())
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun varInt(value: Long): ByteArray {
|
||||||
val buffer = ByteBuffer.allocate(9)
|
val buffer = ByteBuffer.allocate(9)
|
||||||
varInt(value, buffer)
|
varInt(value, buffer)
|
||||||
buffer.flip()
|
buffer.flip()
|
||||||
return Bytes.truncate(buffer.array(), buffer.limit())
|
return Bytes.truncate(buffer.array(), buffer.limit())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic @JvmOverloads fun varInt(value: Int, stream: OutputStream, counter: AccessCounter? = null) = varInt(value.toLong(), stream, counter)
|
@JvmStatic
|
||||||
@JvmStatic @JvmOverloads fun varInt(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
|
@JvmOverloads
|
||||||
|
fun varInt(value: Int, stream: OutputStream, counter: AccessCounter? = null) = varInt(value.toLong(), stream, counter)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun varInt(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
|
||||||
val buffer = ByteBuffer.allocate(9)
|
val buffer = ByteBuffer.allocate(9)
|
||||||
varInt(value, buffer)
|
varInt(value, buffer)
|
||||||
buffer.flip()
|
buffer.flip()
|
||||||
@ -80,46 +93,76 @@ object Encode {
|
|||||||
AccessCounter.inc(counter, buffer.limit())
|
AccessCounter.inc(counter, buffer.limit())
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic @JvmOverloads fun int8(value: Long, stream: OutputStream, counter: AccessCounter? = null) = int8(value.toInt(), stream, counter)
|
@JvmStatic
|
||||||
@JvmStatic @JvmOverloads fun int8(value: Int, stream: OutputStream, counter: AccessCounter? = null) {
|
@JvmOverloads
|
||||||
|
fun int8(value: Long, stream: OutputStream, counter: AccessCounter? = null) = int8(value.toInt(), stream, counter)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun int8(value: Int, stream: OutputStream, counter: AccessCounter? = null) {
|
||||||
stream.write(value)
|
stream.write(value)
|
||||||
AccessCounter.inc(counter)
|
AccessCounter.inc(counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic @JvmOverloads fun int16(value: Long, stream: OutputStream, counter: AccessCounter? = null) = int16(value.toShort(), stream, counter)
|
@JvmStatic
|
||||||
@JvmStatic @JvmOverloads fun int16(value: Int, stream: OutputStream, counter: AccessCounter? = null) = int16(value.toShort(), stream, counter)
|
@JvmOverloads
|
||||||
@JvmStatic @JvmOverloads fun int16(value: Short, stream: OutputStream, counter: AccessCounter? = null) {
|
fun int16(value: Long, stream: OutputStream, counter: AccessCounter? = null) = int16(value.toShort(), stream, counter)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun int16(value: Int, stream: OutputStream, counter: AccessCounter? = null) = int16(value.toShort(), stream, counter)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun int16(value: Short, stream: OutputStream, counter: AccessCounter? = null) {
|
||||||
stream.write(ByteBuffer.allocate(2).putShort(value).array())
|
stream.write(ByteBuffer.allocate(2).putShort(value).array())
|
||||||
AccessCounter.inc(counter, 2)
|
AccessCounter.inc(counter, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun int16(value: Long, buffer: ByteBuffer) = int16(value.toShort(), buffer)
|
@JvmStatic
|
||||||
@JvmStatic fun int16(value: Int, buffer: ByteBuffer) = int16(value.toShort(), buffer)
|
fun int16(value: Long, buffer: ByteBuffer) = int16(value.toShort(), buffer)
|
||||||
@JvmStatic fun int16(value: Short, buffer: ByteBuffer) {
|
|
||||||
|
@JvmStatic
|
||||||
|
fun int16(value: Int, buffer: ByteBuffer) = int16(value.toShort(), buffer)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun int16(value: Short, buffer: ByteBuffer) {
|
||||||
buffer.putShort(value)
|
buffer.putShort(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic @JvmOverloads fun int32(value: Long, stream: OutputStream, counter: AccessCounter? = null) = int32(value.toInt(), stream, counter)
|
@JvmStatic
|
||||||
@JvmStatic @JvmOverloads fun int32(value: Int, stream: OutputStream, counter: AccessCounter? = null) {
|
@JvmOverloads
|
||||||
|
fun int32(value: Long, stream: OutputStream, counter: AccessCounter? = null) = int32(value.toInt(), stream, counter)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun int32(value: Int, stream: OutputStream, counter: AccessCounter? = null) {
|
||||||
stream.write(ByteBuffer.allocate(4).putInt(value).array())
|
stream.write(ByteBuffer.allocate(4).putInt(value).array())
|
||||||
AccessCounter.inc(counter, 4)
|
AccessCounter.inc(counter, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun int32(value: Long, buffer: ByteBuffer) = int32(value.toInt(), buffer)
|
@JvmStatic
|
||||||
@JvmStatic fun int32(value: Int, buffer: ByteBuffer) {
|
fun int32(value: Long, buffer: ByteBuffer) = int32(value.toInt(), buffer)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun int32(value: Int, buffer: ByteBuffer) {
|
||||||
buffer.putInt(value)
|
buffer.putInt(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic @JvmOverloads fun int64(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun int64(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
|
||||||
stream.write(ByteBuffer.allocate(8).putLong(value).array())
|
stream.write(ByteBuffer.allocate(8).putLong(value).array())
|
||||||
AccessCounter.inc(counter, 8)
|
AccessCounter.inc(counter, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun int64(value: Long, buffer: ByteBuffer) {
|
@JvmStatic
|
||||||
|
fun int64(value: Long, buffer: ByteBuffer) {
|
||||||
buffer.putLong(value)
|
buffer.putLong(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varString(value: String, out: OutputStream) {
|
@JvmStatic
|
||||||
|
fun varString(value: String, out: OutputStream) {
|
||||||
val bytes = value.toByteArray(charset("utf-8"))
|
val bytes = value.toByteArray(charset("utf-8"))
|
||||||
// Technically, it says the length in characters, but I think this one might be correct.
|
// Technically, it says the length in characters, but I think this one might be correct.
|
||||||
// It doesn't really matter, as only ASCII characters are being used.
|
// It doesn't really matter, as only ASCII characters are being used.
|
||||||
@ -128,7 +171,8 @@ object Encode {
|
|||||||
out.write(bytes)
|
out.write(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varString(value: String, buffer: ByteBuffer) {
|
@JvmStatic
|
||||||
|
fun varString(value: String, buffer: ByteBuffer) {
|
||||||
val bytes = value.toByteArray()
|
val bytes = value.toByteArray()
|
||||||
// Technically, it says the length in characters, but I think this one might be correct.
|
// Technically, it says the length in characters, but I think this one might be correct.
|
||||||
// It doesn't really matter, as only ASCII characters are being used.
|
// It doesn't really matter, as only ASCII characters are being used.
|
||||||
@ -137,12 +181,14 @@ object Encode {
|
|||||||
buffer.put(bytes)
|
buffer.put(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varBytes(data: ByteArray, out: OutputStream) {
|
@JvmStatic
|
||||||
|
fun varBytes(data: ByteArray, out: OutputStream) {
|
||||||
varInt(data.size.toLong(), out)
|
varInt(data.size.toLong(), out)
|
||||||
out.write(data)
|
out.write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun varBytes(data: ByteArray, buffer: ByteBuffer) {
|
@JvmStatic
|
||||||
|
fun varBytes(data: ByteArray, buffer: ByteBuffer) {
|
||||||
varInt(data.size.toLong(), buffer)
|
varInt(data.size.toLong(), buffer)
|
||||||
buffer.put(data)
|
buffer.put(data)
|
||||||
}
|
}
|
||||||
@ -152,9 +198,10 @@ object Encode {
|
|||||||
* @param streamable the object to be serialized
|
* @param streamable the object to be serialized
|
||||||
* @return an array of bytes representing the given streamable object.
|
* @return an array of bytes representing the given streamable object.
|
||||||
*/
|
*/
|
||||||
@JvmStatic fun bytes(streamable: Streamable): ByteArray {
|
@JvmStatic
|
||||||
|
fun bytes(streamable: Streamable): ByteArray {
|
||||||
val stream = ByteArrayOutputStream()
|
val stream = ByteArrayOutputStream()
|
||||||
streamable.write(stream)
|
streamable.writer().write(stream)
|
||||||
return stream.toByteArray()
|
return stream.toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,9 +210,10 @@ object Encode {
|
|||||||
* @param padding the result will be padded such that its length is a multiple of *padding*
|
* @param padding the result will be padded such that its length is a multiple of *padding*
|
||||||
* @return the bytes of the given [Streamable] object, 0-padded such that the final length is x*padding.
|
* @return the bytes of the given [Streamable] object, 0-padded such that the final length is x*padding.
|
||||||
*/
|
*/
|
||||||
@JvmStatic fun bytes(streamable: Streamable, padding: Int): ByteArray {
|
@JvmStatic
|
||||||
|
fun bytes(streamable: Streamable, padding: Int): ByteArray {
|
||||||
val stream = ByteArrayOutputStream()
|
val stream = ByteArrayOutputStream()
|
||||||
streamable.write(stream)
|
streamable.writer().write(stream)
|
||||||
val offset = padding - stream.size() % padding
|
val offset = padding - stream.size() % padding
|
||||||
val length = stream.size() + offset
|
val length = stream.size() + offset
|
||||||
val result = ByteArray(length)
|
val result = ByteArray(length)
|
||||||
|
@ -86,7 +86,7 @@ class SerializationTest : TestBase() {
|
|||||||
.signature(ByteArray(0))
|
.signature(ByteArray(0))
|
||||||
.build()
|
.build()
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
expected.write(out)
|
expected.writer().write(out)
|
||||||
val `in` = ByteArrayInputStream(out.toByteArray())
|
val `in` = ByteArrayInputStream(out.toByteArray())
|
||||||
val actual = Plaintext.read(MSG, `in`)
|
val actual = Plaintext.read(MSG, `in`)
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ class SerializationTest : TestBase() {
|
|||||||
.signature(ByteArray(0))
|
.signature(ByteArray(0))
|
||||||
.build()
|
.build()
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
expected.write(out)
|
expected.writer().write(out)
|
||||||
val `in` = ByteArrayInputStream(out.toByteArray())
|
val `in` = ByteArrayInputStream(out.toByteArray())
|
||||||
val actual = Plaintext.read(MSG, `in`)
|
val actual = Plaintext.read(MSG, `in`)
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ class SerializationTest : TestBase() {
|
|||||||
assertNotNull(ackMessage1)
|
assertNotNull(ackMessage1)
|
||||||
|
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
expected.write(out)
|
expected.writer().write(out)
|
||||||
val `in` = ByteArrayInputStream(out.toByteArray())
|
val `in` = ByteArrayInputStream(out.toByteArray())
|
||||||
val actual = Plaintext.read(MSG, `in`)
|
val actual = Plaintext.read(MSG, `in`)
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ class SerializationTest : TestBase() {
|
|||||||
val inv = Inv(ivs)
|
val inv = Inv(ivs)
|
||||||
val before = NetworkMessage(inv)
|
val before = NetworkMessage(inv)
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
before.write(out)
|
before.writer().write(out)
|
||||||
|
|
||||||
val after = Factory.getNetworkMessage(3, ByteArrayInputStream(out.toByteArray()))
|
val after = Factory.getNetworkMessage(3, ByteArrayInputStream(out.toByteArray()))
|
||||||
assertNotNull(after)
|
assertNotNull(after)
|
||||||
@ -173,7 +173,7 @@ class SerializationTest : TestBase() {
|
|||||||
val objectMessage = Factory.getObjectMessage(version, `in`, data.size)
|
val objectMessage = Factory.getObjectMessage(version, `in`, data.size)
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
assertNotNull(objectMessage)
|
assertNotNull(objectMessage)
|
||||||
objectMessage!!.write(out)
|
objectMessage!!.writer().write(out)
|
||||||
assertArrayEquals(data, out.toByteArray())
|
assertArrayEquals(data, out.toByteArray())
|
||||||
assertEquals(expectedPayloadType.canonicalName, objectMessage.payload.javaClass.canonicalName)
|
assertEquals(expectedPayloadType.canonicalName, objectMessage.payload.javaClass.canonicalName)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import ch.dissem.bitmessage.ports.NodeRegistry;
|
|||||||
import ch.dissem.bitmessage.repository.*;
|
import ch.dissem.bitmessage.repository.*;
|
||||||
import ch.dissem.bitmessage.wif.WifExporter;
|
import ch.dissem.bitmessage.wif.WifExporter;
|
||||||
import ch.dissem.bitmessage.wif.WifImporter;
|
import ch.dissem.bitmessage.wif.WifImporter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.kohsuke.args4j.CmdLineException;
|
import org.kohsuke.args4j.CmdLineException;
|
||||||
import org.kohsuke.args4j.CmdLineParser;
|
import org.kohsuke.args4j.CmdLineParser;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
@ -68,12 +69,28 @@ public class Main {
|
|||||||
if (options.localPort != null) {
|
if (options.localPort != null) {
|
||||||
ctxBuilder.nodeRegistry(new NodeRegistry() {
|
ctxBuilder.nodeRegistry(new NodeRegistry() {
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void cleanup() {
|
||||||
// NO OP
|
// NO OP
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
public void remove(@NotNull NetworkAddress node) {
|
||||||
|
// NO OP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(@NotNull NetworkAddress node) {
|
||||||
|
// NO OP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
// NO OP
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<NetworkAddress> getKnownAddresses(int limit, @NotNull long... streams) {
|
||||||
return Arrays.stream(streams)
|
return Arrays.stream(streams)
|
||||||
.mapToObj(s -> new NetworkAddress.Builder()
|
.mapToObj(s -> new NetworkAddress.Builder()
|
||||||
.ipv4(127, 0, 0, 1)
|
.ipv4(127, 0, 0, 1)
|
||||||
@ -83,7 +100,7 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void offerAddresses(List<NetworkAddress> nodes) {
|
public void offerAddresses(@NotNull List<NetworkAddress> nodes) {
|
||||||
LOG.info("Local node registry ignored offered addresses: " + nodes);
|
LOG.info("Local node registry ignored offered addresses: " + nodes);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,7 @@ package ch.dissem.bitmessage;
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistry;
|
import ch.dissem.bitmessage.ports.NodeRegistry;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -44,13 +45,29 @@ class TestNodeRegistry implements NodeRegistry {
|
|||||||
// NO OP
|
// NO OP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
public List<NetworkAddress> getKnownAddresses(int limit, @NotNull long... streams) {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void offerAddresses(List<NetworkAddress> nodes) {
|
public void offerAddresses(@NotNull List<NetworkAddress> nodes) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(@NotNull NetworkAddress node) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull NetworkAddress node) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup() {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ dependencies {
|
|||||||
compile 'org.slf4j:slf4j-api'
|
compile 'org.slf4j:slf4j-api'
|
||||||
compile 'com.beust:klaxon'
|
compile 'com.beust:klaxon'
|
||||||
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit'
|
||||||
testCompile 'org.hamcrest:hamcrest-library:1.3'
|
testCompile 'org.hamcrest:hamcrest-library'
|
||||||
testCompile 'com.nhaarman:mockito-kotlin:1.5.0'
|
testCompile 'com.nhaarman:mockito-kotlin'
|
||||||
testCompile project(path: ':core', configuration: 'testArtifacts')
|
testCompile project(path: ':core', configuration: 'testArtifacts')
|
||||||
testCompile project(':cryptography-bc')
|
testCompile project(':cryptography-bc')
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ object ContactExport {
|
|||||||
"subscribed" to it.isSubscribed,
|
"subscribed" to it.isSubscribed,
|
||||||
"pubkey" to it.pubkey?.let {
|
"pubkey" to it.pubkey?.let {
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
it.writeUnencrypted(out)
|
it.writer().writeUnencrypted(out)
|
||||||
Base64.encodeToString(out.toByteArray())
|
Base64.encodeToString(out.toByteArray())
|
||||||
},
|
},
|
||||||
"privateKey" to if (includePrivateKey) {
|
"privateKey" to if (includePrivateKey) {
|
||||||
|
@ -19,6 +19,7 @@ package ch.dissem.bitmessage.extensions
|
|||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
import ch.dissem.bitmessage.entity.CustomMessage
|
import ch.dissem.bitmessage.entity.CustomMessage
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.entity.payload.CryptoBox
|
import ch.dissem.bitmessage.entity.payload.CryptoBox
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey
|
import ch.dissem.bitmessage.entity.payload.Pubkey
|
||||||
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
import ch.dissem.bitmessage.exception.DecryptionFailedException
|
||||||
@ -73,7 +74,7 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
Encode.varInt(privateKey.pubkey.extraBytes, out)
|
Encode.varInt(privateKey.pubkey.extraBytes, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
data?.write(out) ?: throw IllegalStateException("no unencrypted data available")
|
data?.writer()?.write(out) ?: throw IllegalStateException("no unencrypted data available")
|
||||||
Encode.varBytes(cryptography().getSignature(out.toByteArray(), privateKey), out)
|
Encode.varBytes(cryptography().getSignature(out.toByteArray(), privateKey), out)
|
||||||
container = CryptoBox(out.toByteArray(), publicKey)
|
container = CryptoBox(out.toByteArray(), publicKey)
|
||||||
}
|
}
|
||||||
@ -109,9 +110,17 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
return data!!
|
return data!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: CryptoCustomMessage<*>
|
||||||
|
) : CustomMessage.Writer(item) {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
Encode.varString(COMMAND, out)
|
Encode.varString(COMMAND, out)
|
||||||
container?.write(out) ?: throw IllegalStateException("not encrypted yet")
|
item.container?.writer()?.write(out) ?: throw IllegalStateException("not encrypted yet")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Reader<out T> {
|
interface Reader<out T> {
|
||||||
@ -136,9 +145,11 @@ class CryptoCustomMessage<T : Streamable> : CustomMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField val COMMAND = "ENCRYPTED"
|
@JvmField
|
||||||
|
val COMMAND = "ENCRYPTED"
|
||||||
|
|
||||||
@JvmStatic fun <T : Streamable> read(data: CustomMessage, dataReader: Reader<T>): CryptoCustomMessage<T> {
|
@JvmStatic
|
||||||
|
fun <T : Streamable> read(data: CustomMessage, dataReader: Reader<T>): CryptoCustomMessage<T> {
|
||||||
val cryptoBox = CryptoBox.read(ByteArrayInputStream(data.getData()), data.getData().size)
|
val cryptoBox = CryptoBox.read(ByteArrayInputStream(data.getData()), data.getData().size)
|
||||||
return CryptoCustomMessage(cryptoBox, dataReader)
|
return CryptoCustomMessage(cryptoBox, dataReader)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package ch.dissem.bitmessage.extensions.pow
|
|||||||
|
|
||||||
import ch.dissem.bitmessage.entity.BitmessageAddress
|
import ch.dissem.bitmessage.entity.BitmessageAddress
|
||||||
import ch.dissem.bitmessage.entity.Streamable
|
import ch.dissem.bitmessage.entity.Streamable
|
||||||
|
import ch.dissem.bitmessage.entity.StreamableWriter
|
||||||
import ch.dissem.bitmessage.extensions.CryptoCustomMessage
|
import ch.dissem.bitmessage.extensions.CryptoCustomMessage
|
||||||
import ch.dissem.bitmessage.utils.Decode.bytes
|
import ch.dissem.bitmessage.utils.Decode.bytes
|
||||||
import ch.dissem.bitmessage.utils.Decode.varBytes
|
import ch.dissem.bitmessage.utils.Decode.varBytes
|
||||||
@ -33,16 +34,24 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
data class ProofOfWorkRequest @JvmOverloads constructor(val sender: BitmessageAddress, val initialHash: ByteArray, val request: ProofOfWorkRequest.Request, val data: ByteArray = ByteArray(0)) : Streamable {
|
data class ProofOfWorkRequest @JvmOverloads constructor(val sender: BitmessageAddress, val initialHash: ByteArray, val request: ProofOfWorkRequest.Request, val data: ByteArray = ByteArray(0)) : Streamable {
|
||||||
|
|
||||||
|
override fun writer(): StreamableWriter = Writer(this)
|
||||||
|
|
||||||
|
private class Writer(
|
||||||
|
private val item: ProofOfWorkRequest
|
||||||
|
) : StreamableWriter {
|
||||||
|
|
||||||
override fun write(out: OutputStream) {
|
override fun write(out: OutputStream) {
|
||||||
out.write(initialHash)
|
out.write(item.initialHash)
|
||||||
Encode.varString(request.name, out)
|
Encode.varString(item.request.name, out)
|
||||||
Encode.varBytes(data, out)
|
Encode.varBytes(item.data, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun write(buffer: ByteBuffer) {
|
override fun write(buffer: ByteBuffer) {
|
||||||
buffer.put(initialHash)
|
buffer.put(item.initialHash)
|
||||||
Encode.varString(request.name, buffer)
|
Encode.varString(item.request.name, buffer)
|
||||||
Encode.varBytes(data, buffer)
|
Encode.varBytes(item.data, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Reader(private val identity: BitmessageAddress) : CryptoCustomMessage.Reader<ProofOfWorkRequest> {
|
class Reader(private val identity: BitmessageAddress) : CryptoCustomMessage.Reader<ProofOfWorkRequest> {
|
||||||
|
@ -43,7 +43,7 @@ class CryptoCustomMessageTest : TestBase() {
|
|||||||
messageBefore.signAndEncrypt(sendingIdentity, cryptography().createPublicKey(sendingIdentity.publicDecryptionKey))
|
messageBefore.signAndEncrypt(sendingIdentity, cryptography().createPublicKey(sendingIdentity.publicDecryptionKey))
|
||||||
|
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
messageBefore.write(out)
|
messageBefore.writer().write(out)
|
||||||
val `in` = ByteArrayInputStream(out.toByteArray())
|
val `in` = ByteArrayInputStream(out.toByteArray())
|
||||||
|
|
||||||
val customMessage = CustomMessage.read(`in`, out.size())
|
val customMessage = CustomMessage.read(`in`, out.size())
|
||||||
@ -71,7 +71,7 @@ class CryptoCustomMessageTest : TestBase() {
|
|||||||
|
|
||||||
|
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
messageBefore.write(out)
|
messageBefore.writer().write(out)
|
||||||
val `in` = ByteArrayInputStream(out.toByteArray())
|
val `in` = ByteArrayInputStream(out.toByteArray())
|
||||||
|
|
||||||
val customMessage = CustomMessage.read(`in`, out.size())
|
val customMessage = CustomMessage.read(`in`, out.size())
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
#Mon Jul 17 06:32:41 CEST 2017
|
#Tue Nov 07 17:21:36 CET 2017
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-all.zip
|
||||||
|
6
gradlew
vendored
6
gradlew
vendored
@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
|
|||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD="maximum"
|
||||||
|
|
||||||
warn ( ) {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
}
|
||||||
|
|
||||||
die ( ) {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
@ -155,7 +155,7 @@ if $cygwin ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Escape application args
|
||||||
save ( ) {
|
save () {
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
echo " "
|
echo " "
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class ConnectionIO(
|
|||||||
if (!headerOut.hasRemaining() && !sendingQueue.isEmpty()) {
|
if (!headerOut.hasRemaining() && !sendingQueue.isEmpty()) {
|
||||||
headerOut.clear()
|
headerOut.clear()
|
||||||
val payload = sendingQueue.poll()
|
val payload = sendingQueue.poll()
|
||||||
payloadOut = NetworkMessage(payload).writeHeaderAndGetPayloadBuffer(headerOut)
|
payloadOut = NetworkMessage(payload).writer().writeHeaderAndGetPayloadBuffer(headerOut)
|
||||||
headerOut.flip()
|
headerOut.flip()
|
||||||
lastUpdate = System.currentTimeMillis()
|
lastUpdate = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ class NioNetworkHandler : NetworkHandler, InternalContext.ContextHolder {
|
|||||||
SocketChannel.open(InetSocketAddress(server, port)).use { channel ->
|
SocketChannel.open(InetSocketAddress(server, port)).use { channel ->
|
||||||
channel.configureBlocking(true)
|
channel.configureBlocking(true)
|
||||||
val headerBuffer = ByteBuffer.allocate(HEADER_SIZE)
|
val headerBuffer = ByteBuffer.allocate(HEADER_SIZE)
|
||||||
val payloadBuffer = NetworkMessage(request).writeHeaderAndGetPayloadBuffer(headerBuffer)
|
val payloadBuffer = NetworkMessage(request).writer().writeHeaderAndGetPayloadBuffer(headerBuffer)
|
||||||
headerBuffer.flip()
|
headerBuffer.flip()
|
||||||
while (headerBuffer.hasRemaining()) {
|
while (headerBuffer.hasRemaining()) {
|
||||||
channel.write(headerBuffer)
|
channel.write(headerBuffer)
|
||||||
|
@ -38,4 +38,16 @@ internal class TestNodeRegistry(vararg nodes: NetworkAddress) : NodeRegistry {
|
|||||||
override fun offerAddresses(nodes: List<NetworkAddress>) {
|
override fun offerAddresses(nodes: List<NetworkAddress>) {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun update(node: NetworkAddress) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(node: NetworkAddress) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cleanup() {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRep
|
|||||||
private fun writePubkey(ps: PreparedStatement, parameterIndex: Int, data: Pubkey?) {
|
private fun writePubkey(ps: PreparedStatement, parameterIndex: Int, data: Pubkey?) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
val out = ByteArrayOutputStream()
|
val out = ByteArrayOutputStream()
|
||||||
data.writeUnencrypted(out)
|
data.writer().writeUnencrypted(out)
|
||||||
ps.setBytes(parameterIndex, out.toByteArray())
|
ps.setBytes(parameterIndex, out.toByteArray())
|
||||||
} else {
|
} else {
|
||||||
ps.setBytes(parameterIndex, null)
|
ps.setBytes(parameterIndex, null)
|
||||||
|
@ -30,7 +30,7 @@ abstract class JdbcHelper protected constructor(@JvmField protected val config:
|
|||||||
ps.setBytes(parameterIndex, null)
|
ps.setBytes(parameterIndex, null)
|
||||||
} else {
|
} else {
|
||||||
val os = ByteArrayOutputStream()
|
val os = ByteArrayOutputStream()
|
||||||
data.write(os)
|
data.writer().write(os)
|
||||||
ps.setBytes(parameterIndex, os.toByteArray())
|
ps.setBytes(parameterIndex, os.toByteArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,8 @@ package ch.dissem.bitmessage.repository
|
|||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistry
|
import ch.dissem.bitmessage.ports.NodeRegistry
|
||||||
import ch.dissem.bitmessage.ports.NodeRegistryHelper.loadStableNodes
|
import ch.dissem.bitmessage.ports.NodeRegistryHelper.loadStableNodes
|
||||||
|
import ch.dissem.bitmessage.utils.*
|
||||||
import ch.dissem.bitmessage.utils.Collections
|
import ch.dissem.bitmessage.utils.Collections
|
||||||
import ch.dissem.bitmessage.utils.SqlStrings
|
|
||||||
import ch.dissem.bitmessage.utils.Strings
|
|
||||||
import ch.dissem.bitmessage.utils.UnixTime.DAY
|
import ch.dissem.bitmessage.utils.UnixTime.DAY
|
||||||
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
|
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
|
||||||
import ch.dissem.bitmessage.utils.UnixTime.now
|
import ch.dissem.bitmessage.utils.UnixTime.now
|
||||||
@ -155,7 +154,18 @@ class JdbcNodeRegistry(config: JdbcConfig) : JdbcHelper(config), NodeRegistry {
|
|||||||
ps.setBytes(2, node.IPv6)
|
ps.setBytes(2, node.IPv6)
|
||||||
ps.setInt(3, node.port)
|
ps.setInt(3, node.port)
|
||||||
ps.setLong(4, node.services)
|
ps.setLong(4, node.services)
|
||||||
ps.setLong(5, node.time)
|
ps.setLong(5,
|
||||||
|
if (node.time > UnixTime.now) {
|
||||||
|
// This might be an attack, let's not use those nodes with priority
|
||||||
|
UnixTime.now - 7 * UnixTime.DAY
|
||||||
|
} else if (node.time == 0L) {
|
||||||
|
// Those just don't have a time set
|
||||||
|
// let's give them slightly higher priority than the possible attack ones
|
||||||
|
UnixTime.now - 6 * UnixTime.DAY
|
||||||
|
} else {
|
||||||
|
node.time
|
||||||
|
}
|
||||||
|
)
|
||||||
ps.executeUpdate()
|
ps.executeUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,13 +174,20 @@ class JdbcNodeRegistry(config: JdbcConfig) : JdbcHelper(config), NodeRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun update(node: NetworkAddress) {
|
override fun update(node: NetworkAddress) {
|
||||||
try {
|
try {
|
||||||
|
val time = if (node.time > UnixTime.now) {
|
||||||
|
// This might be an attack, let's not use those nodes with priority
|
||||||
|
UnixTime.now - 7 * UnixTime.DAY
|
||||||
|
} else {
|
||||||
|
node.time
|
||||||
|
}
|
||||||
|
|
||||||
config.getConnection().use { connection ->
|
config.getConnection().use { connection ->
|
||||||
connection.prepareStatement(
|
connection.prepareStatement(
|
||||||
"UPDATE Node SET services=?, time=? WHERE stream=? AND address=? AND port=?").use { ps ->
|
"UPDATE Node SET services=?, time=? WHERE stream=? AND address=? AND port=?").use { ps ->
|
||||||
ps.setLong(1, node.services)
|
ps.setLong(1, node.services)
|
||||||
ps.setLong(2, node.time)
|
ps.setLong(2, max(node.time, time))
|
||||||
ps.setLong(3, node.stream)
|
ps.setLong(3, node.stream)
|
||||||
ps.setBytes(4, node.IPv6)
|
ps.setBytes(4, node.IPv6)
|
||||||
ps.setInt(5, node.port)
|
ps.setInt(5, node.port)
|
||||||
@ -182,6 +199,36 @@ class JdbcNodeRegistry(config: JdbcConfig) : JdbcHelper(config), NodeRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun remove(node: NetworkAddress) {
|
||||||
|
try {
|
||||||
|
config.getConnection().use { connection ->
|
||||||
|
connection.prepareStatement(
|
||||||
|
"DELETE FROM Node WHERE stream=? AND address=? AND port=?").use { ps ->
|
||||||
|
ps.setLong(1, node.stream)
|
||||||
|
ps.setBytes(2, node.IPv6)
|
||||||
|
ps.setInt(3, node.port)
|
||||||
|
ps.executeUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
LOG.error(e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cleanup() {
|
||||||
|
try {
|
||||||
|
config.getConnection().use { connection ->
|
||||||
|
connection.prepareStatement(
|
||||||
|
"DELETE FROM Node WHERE time<?").use { ps ->
|
||||||
|
ps.setLong(1, UnixTime.now - 8 * DAY)
|
||||||
|
ps.executeUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
LOG.error(e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG = LoggerFactory.getLogger(JdbcNodeRegistry::class.java)
|
private val LOG = LoggerFactory.getLogger(JdbcNodeRegistry::class.java)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user