Fixes and improvements, SystemTest still broken

This commit is contained in:
2017-06-16 07:03:12 +02:00
parent 1d3340a547
commit 894e0ff724
62 changed files with 1364 additions and 1276 deletions

View File

@ -58,7 +58,53 @@ import kotlin.properties.Delegates
*
* The port defaults to 8444 (the default Bitmessage port)
*/
class BitmessageContext private constructor(builder: BitmessageContext.Builder) {
class BitmessageContext(
cryptography: Cryptography,
inventory: Inventory,
nodeRegistry: NodeRegistry,
networkHandler: NetworkHandler,
addressRepository: AddressRepository,
messageRepository: MessageRepository,
proofOfWorkRepository: ProofOfWorkRepository,
proofOfWorkEngine: ProofOfWorkEngine = MultiThreadedPOWEngine(),
customCommandHandler: CustomCommandHandler = object : CustomCommandHandler {
override fun handle(request: CustomMessage): MessagePayload? {
BitmessageContext.LOG.debug("Received custom request, but no custom command handler configured.")
return null
}
},
listener: Listener,
labeler: Labeler = DefaultLabeler(),
port: Int = 8444,
connectionTTL: Long = 30 * MINUTE,
connectionLimit: Int = 150,
sendPubkeyOnIdentityCreation: Boolean,
doMissingProofOfWorkDelayInSeconds: Int = 30
) {
private constructor(builder: BitmessageContext.Builder) : this(
builder.cryptography,
builder.inventory,
builder.nodeRegistry,
builder.networkHandler,
builder.addressRepo,
builder.messageRepo,
builder.proofOfWorkRepository,
builder.proofOfWorkEngine ?: MultiThreadedPOWEngine(),
builder.customCommandHandler ?: object : CustomCommandHandler {
override fun handle(request: CustomMessage): MessagePayload? {
BitmessageContext.LOG.debug("Received custom request, but no custom command handler configured.")
return null
}
},
builder.listener,
builder.labeler ?: DefaultLabeler(),
builder.port,
builder.connectionTTL,
builder.connectionLimit,
builder.sendPubkeyOnIdentityCreation,
builder.doMissingProofOfWorkDelay
)
private val sendPubkeyOnIdentityCreation: Boolean
@ -72,38 +118,10 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
val labeler: Labeler
@JvmName("labeler") get
init {
labeler = builder.labeler ?: DefaultLabeler()
internals = InternalContext(
builder.cryptography,
builder.inventory,
builder.nodeRegistry,
builder.networkHandler,
builder.addressRepo,
builder.messageRepo,
builder.proofOfWorkRepository,
builder.proofOfWorkEngine ?: MultiThreadedPOWEngine(),
builder.customCommandHandler ?: object : CustomCommandHandler {
override fun handle(request: CustomMessage): MessagePayload? {
LOG.debug("Received custom request, but no custom command handler configured.")
return null
}
},
builder.listener,
labeler,
builder.port,
builder.connectionTTL,
builder.connectionLimit
)
internals.proofOfWorkService.doMissingProofOfWork(30000) // TODO: this should be configurable
sendPubkeyOnIdentityCreation = builder.sendPubkeyOnIdentityCreation
(builder.listener as? Listener.WithContext)?.setContext(this)
}
val addresses: AddressRepository = internals.addressRepository
val addresses: AddressRepository
@JvmName("addresses") get
val messages: MessageRepository = internals.messageRepository
val messages: MessageRepository
@JvmName("messages") get
fun createIdentity(shorter: Boolean, vararg features: Feature): BitmessageAddress {
@ -285,10 +303,9 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
fun addContact(contact: BitmessageAddress) {
internals.addressRepository.save(contact)
if (contact.pubkey == null) {
internals.addressRepository.getAddress(contact.address)?.let {
if (it.pubkey == null) {
internals.requestPubkey(contact)
}
// If it already existed, the saved contact might have the public key
if (internals.addressRepository.getAddress(contact.address)!!.pubkey == null) {
internals.requestPubkey(contact)
}
}
}
@ -300,13 +317,13 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
}
private fun tryToFindBroadcastsForAddress(address: BitmessageAddress) {
for (`object` in internals.inventory.getObjects(address.stream, Broadcast.getVersion(address), ObjectType.BROADCAST)) {
for (objectMessage in internals.inventory.getObjects(address.stream, Broadcast.getVersion(address), ObjectType.BROADCAST)) {
try {
val broadcast = `object`.payload as Broadcast
val broadcast = objectMessage.payload as Broadcast
broadcast.decrypt(address)
// This decrypts it twice, but on the other hand it doesn't try to decrypt the objects with
// other subscriptions and the interface stays as simple as possible.
internals.networkListener.receive(`object`)
internals.networkListener.receive(objectMessage)
} catch (ignore: DecryptionFailedException) {
} catch (e: Exception) {
LOG.debug(e.message, e)
@ -348,6 +365,7 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
internal var connectionLimit = 150
internal var connectionTTL = 30 * MINUTE
internal var sendPubkeyOnIdentityCreation = true
internal var doMissingProofOfWorkDelay = 30
fun port(port: Int): Builder {
this.port = port
@ -409,6 +427,7 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
return this
}
@JvmName("kotlinListener")
fun listener(listener: (Plaintext) -> Unit): Builder {
this.listener = object : Listener {
override fun receive(plaintext: Plaintext) {
@ -428,6 +447,10 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
return this
}
fun doMissingProofOfWorkDelay(seconds: Int) {
this.doMissingProofOfWorkDelay = seconds
}
/**
* By default a client will send the public key when an identity is being created. On weaker devices
* this behaviour might not be desirable.
@ -438,18 +461,34 @@ class BitmessageContext private constructor(builder: BitmessageContext.Builder)
}
fun build(): BitmessageContext {
nonNull("inventory", inventory)
nonNull("nodeRegistry", nodeRegistry)
nonNull("networkHandler", networkHandler)
nonNull("addressRepo", addressRepo)
nonNull("messageRepo", messageRepo)
nonNull("proofOfWorkRepo", proofOfWorkRepository)
return BitmessageContext(this)
}
}
private fun nonNull(name: String, o: Any?) {
if (o == null) throw IllegalStateException(name + " must not be null")
}
init {
this.labeler = labeler
this.internals = InternalContext(
cryptography,
inventory,
nodeRegistry,
networkHandler,
addressRepository,
messageRepository,
proofOfWorkRepository,
proofOfWorkEngine,
customCommandHandler,
listener,
labeler,
port,
connectionTTL,
connectionLimit
)
this.addresses = addressRepository
this.messages = messageRepository
this.sendPubkeyOnIdentityCreation = sendPubkeyOnIdentityCreation
(listener as? Listener.WithContext)?.setContext(this)
internals.proofOfWorkService.doMissingProofOfWork(doMissingProofOfWorkDelayInSeconds * 1000L)
}
companion object {

View File

@ -25,6 +25,7 @@ import ch.dissem.bitmessage.entity.valueobject.InventoryVector
import ch.dissem.bitmessage.exception.DecryptionFailedException
import ch.dissem.bitmessage.ports.Labeler
import ch.dissem.bitmessage.ports.NetworkHandler
import ch.dissem.bitmessage.utils.Strings.hex
import org.slf4j.LoggerFactory
import java.util.*
@ -32,23 +33,23 @@ internal open class DefaultMessageListener(
private val labeler: Labeler,
private val listener: BitmessageContext.Listener
) : NetworkHandler.MessageListener {
private var ctx by InternalContext
private var ctx by InternalContext.lateinit
override fun receive(`object`: ObjectMessage) {
val payload = `object`.payload
override fun receive(objectMessage: ObjectMessage) {
val payload = objectMessage.payload
when (payload.type) {
ObjectType.GET_PUBKEY -> {
receive(`object`, payload as GetPubkey)
receive(objectMessage, payload as GetPubkey)
}
ObjectType.PUBKEY -> {
receive(`object`, payload as Pubkey)
receive(objectMessage, payload as Pubkey)
}
ObjectType.MSG -> {
receive(`object`, payload as Msg)
receive(objectMessage, payload as Msg)
}
ObjectType.BROADCAST -> {
receive(`object`, payload as Broadcast)
receive(objectMessage, payload as Broadcast)
}
null -> {
if (payload is GenericPayload) {
@ -61,30 +62,33 @@ internal open class DefaultMessageListener(
}
}
protected fun receive(`object`: ObjectMessage, getPubkey: GetPubkey) {
protected fun receive(objectMessage: ObjectMessage, getPubkey: GetPubkey) {
val identity = ctx.addressRepository.findIdentity(getPubkey.ripeTag)
if (identity != null && identity.privateKey != null && !identity.isChan) {
LOG.info("Got pubkey request for identity " + identity)
// FIXME: only send pubkey if it wasn't sent in the last TTL.pubkey() days
ctx.sendPubkey(identity, `object`.stream)
ctx.sendPubkey(identity, objectMessage.stream)
}
}
protected fun receive(`object`: ObjectMessage, pubkey: Pubkey) {
val address: BitmessageAddress?
protected fun receive(objectMessage: ObjectMessage, pubkey: Pubkey) {
try {
if (pubkey is V4Pubkey) {
address = ctx.addressRepository.findContact(pubkey.tag)
if (address != null) {
pubkey.decrypt(address.publicDecryptionKey)
ctx.addressRepository.findContact(pubkey.tag)?.let {
if (it.pubkey == null) {
pubkey.decrypt(it.publicDecryptionKey)
updatePubkey(it, pubkey)
}
}
} else {
address = ctx.addressRepository.findContact(pubkey.ripe)
ctx.addressRepository.findContact(pubkey.ripe)?.let {
if (it.pubkey == null) {
updatePubkey(it, pubkey)
}
}
}
if (address != null && address.pubkey == null) {
updatePubkey(address, pubkey)
}
} catch (_: DecryptionFailedException) {}
} catch (_: DecryptionFailedException) {
}
}
@ -101,19 +105,20 @@ internal open class DefaultMessageListener(
}
}
protected fun receive(`object`: ObjectMessage, msg: Msg) {
protected fun receive(objectMessage: ObjectMessage, msg: Msg) {
for (identity in ctx.addressRepository.getIdentities()) {
try {
msg.decrypt(identity.privateKey!!.privateEncryptionKey)
val plaintext = msg.plaintext!!
plaintext.to = identity
if (!`object`.isSignatureValid(plaintext.from.pubkey!!)) {
LOG.warn("Msg with IV " + `object`.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.")
if (!objectMessage.isSignatureValid(plaintext.from.pubkey!!)) {
LOG.warn("Msg with IV " + objectMessage.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.")
} else {
receive(`object`.inventoryVector, plaintext)
receive(objectMessage.inventoryVector, plaintext)
}
break
} catch (_: DecryptionFailedException) {}
} catch (_: DecryptionFailedException) {
}
}
}
@ -122,11 +127,11 @@ internal open class DefaultMessageListener(
ctx.messageRepository.getMessageForAck(ack.data)?.let {
ctx.labeler.markAsAcknowledged(it)
ctx.messageRepository.save(it)
}
} ?: LOG.debug("Message not found for ack ${hex(ack.data)}")
}
}
protected fun receive(`object`: ObjectMessage, broadcast: Broadcast) {
protected fun receive(objectMessage: ObjectMessage, broadcast: Broadcast) {
val tag = if (broadcast is V5Broadcast) broadcast.tag else null
for (subscription in ctx.addressRepository.getSubscriptions(broadcast.version)) {
if (tag != null && !Arrays.equals(tag, subscription.tag)) {
@ -134,12 +139,13 @@ internal open class DefaultMessageListener(
}
try {
broadcast.decrypt(subscription.publicDecryptionKey)
if (!`object`.isSignatureValid(broadcast.plaintext!!.from.pubkey!!)) {
LOG.warn("Broadcast with IV " + `object`.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.")
if (!objectMessage.isSignatureValid(broadcast.plaintext!!.from.pubkey!!)) {
LOG.warn("Broadcast with IV " + objectMessage.inventoryVector + " was successfully decrypted, but signature check failed. Ignoring.")
} else {
receive(`object`.inventoryVector, broadcast.plaintext!!)
receive(objectMessage.inventoryVector, broadcast.plaintext!!)
}
} catch (_: DecryptionFailedException) {}
} catch (_: DecryptionFailedException) {
}
}
}
@ -158,7 +164,7 @@ internal open class DefaultMessageListener(
msg.ackMessage?.let {
ctx.inventory.storeObject(it)
ctx.networkHandler.offer(it.inventoryVector)
}
} ?: LOG.debug("ack message expected")
}
}

View File

@ -28,7 +28,6 @@ import ch.dissem.bitmessage.utils.UnixTime
import org.slf4j.LoggerFactory
import java.util.*
import java.util.concurrent.Executors
import kotlin.properties.Delegates
import kotlin.reflect.KProperty
/**
@ -68,7 +67,8 @@ class InternalContext(
get() = _streams.toLongArray()
init {
instance = this
lateinit.instance = this
lateinit = ContextDelegate()
Singleton.initialize(cryptography)
// TODO: streams of new identities and subscriptions should also be added. This works only after a restart.
@ -102,24 +102,24 @@ class InternalContext(
val recipient = to ?: from
val expires = UnixTime.now + timeToLive
LOG.info("Expires at " + expires)
val `object` = ObjectMessage(
val objectMessage = ObjectMessage(
stream = recipient.stream,
expiresTime = expires,
payload = payload
)
if (`object`.isSigned) {
`object`.sign(
if (objectMessage.isSigned) {
objectMessage.sign(
from.privateKey ?: throw IllegalArgumentException("The given sending address is no identity")
)
}
if (payload is Broadcast) {
payload.encrypt()
} else if (payload is Encrypted) {
`object`.encrypt(
objectMessage.encrypt(
recipient.pubkey ?: throw IllegalArgumentException("The public key for the recipient isn't available")
)
}
proofOfWorkService.doProofOfWork(to, `object`)
proofOfWorkService.doProofOfWork(to, objectMessage)
}
fun sendPubkey(identity: BitmessageAddress, targetStream: Long) {
@ -163,12 +163,11 @@ class InternalContext(
}
val expires = UnixTime.now + TTL.getpubkey
LOG.info("Expires at " + expires)
val payload = GetPubkey(contact)
LOG.info("Expires at $expires")
val request = ObjectMessage(
stream = contact.stream,
expiresTime = expires,
payload = payload
payload = GetPubkey(contact)
)
proofOfWorkService.doProofOfWork(request)
}
@ -179,14 +178,14 @@ class InternalContext(
address.alias = it.alias
address.isSubscribed = it.isSubscribed
}
for (`object` in inventory.getObjects(address.stream, address.version, ObjectType.PUBKEY)) {
for (objectMessage in inventory.getObjects(address.stream, address.version, ObjectType.PUBKEY)) {
try {
val pubkey = `object`.payload as Pubkey
val pubkey = objectMessage.payload as Pubkey
if (address.version == 4L) {
val v4Pubkey = pubkey as V4Pubkey
if (Arrays.equals(address.tag, v4Pubkey.tag)) {
v4Pubkey.decrypt(address.publicDecryptionKey)
if (`object`.isSignatureValid(v4Pubkey)) {
if (objectMessage.isSignatureValid(v4Pubkey)) {
address.pubkey = v4Pubkey
addressRepository.save(address)
break
@ -219,17 +218,19 @@ class InternalContext(
fun setContext(context: InternalContext)
}
class ContextDelegate {
internal lateinit var instance: InternalContext
operator fun getValue(thisRef: Any?, property: KProperty<*>) = instance
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: InternalContext) {}
}
companion object {
private val LOG = LoggerFactory.getLogger(InternalContext::class.java)
@JvmField val NETWORK_NONCE_TRIALS_PER_BYTE: Long = 1000
@JvmField val NETWORK_EXTRA_BYTES: Long = 1000
private var instance: InternalContext by Delegates.notNull<InternalContext>()
operator fun getValue(thisRef: Any?, property: KProperty<*>) = instance
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: InternalContext) {
instance = value
}
var lateinit = ContextDelegate()
private set
}
}

View File

@ -22,6 +22,7 @@ import ch.dissem.bitmessage.entity.*
import ch.dissem.bitmessage.entity.payload.Msg
import ch.dissem.bitmessage.ports.ProofOfWorkEngine
import ch.dissem.bitmessage.ports.ProofOfWorkRepository.Item
import ch.dissem.bitmessage.utils.Strings
import org.slf4j.LoggerFactory
import java.io.IOException
import java.util.*
@ -31,7 +32,7 @@ import java.util.*
*/
class ProofOfWorkService : ProofOfWorkEngine.Callback {
private val ctx by InternalContext
private val ctx by InternalContext.lateinit
private val cryptography by lazy { ctx.cryptography }
private val powRepo by lazy { ctx.proofOfWorkRepository }
private val messageRepo by lazy { ctx.messageRepository }
@ -45,75 +46,69 @@ class ProofOfWorkService : ProofOfWorkEngine.Callback {
override fun run() {
LOG.info("Doing POW for " + items.size + " tasks.")
for (initialHash in items) {
val (`object`, nonceTrialsPerByte, extraBytes) = powRepo.getItem(initialHash)
cryptography.doProofOfWork(`object`, nonceTrialsPerByte, extraBytes,
val (objectMessage, nonceTrialsPerByte, extraBytes) = powRepo.getItem(initialHash)
cryptography.doProofOfWork(objectMessage, nonceTrialsPerByte, extraBytes,
this@ProofOfWorkService)
}
}
}, delayInMilliseconds)
}
fun doProofOfWork(`object`: ObjectMessage) {
doProofOfWork(null, `object`)
fun doProofOfWork(objectMessage: ObjectMessage) {
doProofOfWork(null, objectMessage)
}
fun doProofOfWork(recipient: BitmessageAddress?, `object`: ObjectMessage) {
fun doProofOfWork(recipient: BitmessageAddress?, objectMessage: ObjectMessage) {
val pubkey = recipient?.pubkey
val nonceTrialsPerByte = pubkey?.nonceTrialsPerByte ?: NETWORK_NONCE_TRIALS_PER_BYTE
val extraBytes = pubkey?.extraBytes ?: NETWORK_EXTRA_BYTES
powRepo.putObject(`object`, nonceTrialsPerByte, extraBytes)
if (`object`.payload is PlaintextHolder) {
`object`.payload.plaintext?.let {
it.initialHash = cryptography.getInitialHash(`object`)
powRepo.putObject(objectMessage, nonceTrialsPerByte, extraBytes)
if (objectMessage.payload is PlaintextHolder) {
objectMessage.payload.plaintext?.let {
it.initialHash = cryptography.getInitialHash(objectMessage)
messageRepo.save(it)
}
} ?: LOG.error("PlaintextHolder without Plaintext shouldn't make it to the POW")
}
cryptography.doProofOfWork(`object`, nonceTrialsPerByte, extraBytes, this)
cryptography.doProofOfWork(objectMessage, nonceTrialsPerByte, extraBytes, this)
}
fun doProofOfWorkWithAck(plaintext: Plaintext, expirationTime: Long) {
val ack = plaintext.ackMessage
val ack = plaintext.ackMessage!!
messageRepo.save(plaintext)
val item = Item(ack!!, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES,
val item = Item(ack, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES,
expirationTime, plaintext)
powRepo.putObject(item)
cryptography.doProofOfWork(ack, NETWORK_NONCE_TRIALS_PER_BYTE, NETWORK_EXTRA_BYTES, this)
}
override fun onNonceCalculated(initialHash: ByteArray, nonce: ByteArray) {
val (`object`, _, _, expirationTime, message) = powRepo.getItem(initialHash)
val (objectMessage, _, _, expirationTime, message) = powRepo.getItem(initialHash)
if (message == null) {
`object`.nonce = nonce
objectMessage.nonce = nonce
messageRepo.getMessage(initialHash)?.let {
it.inventoryVector = `object`.inventoryVector
it.inventoryVector = objectMessage.inventoryVector
it.updateNextTry()
ctx.labeler.markAsSent(it)
messageRepo.save(it)
}
try {
ctx.networkListener.receive(`object`)
} catch (e: IOException) {
LOG.debug(e.message, e)
}
ctx.inventory.storeObject(`object`)
ctx.networkHandler.offer(`object`.inventoryVector)
ctx.inventory.storeObject(objectMessage)
ctx.networkHandler.offer(objectMessage.inventoryVector)
} else {
message.ackMessage!!.nonce = nonce
val `object` = ObjectMessage.Builder()
val newObjectMessage = ObjectMessage.Builder()
.stream(message.stream)
.expiresTime(expirationTime!!)
.payload(Msg(message))
.build()
if (`object`.isSigned) {
`object`.sign(message.from.privateKey!!)
if (newObjectMessage.isSigned) {
newObjectMessage.sign(message.from.privateKey!!)
}
if (`object`.payload is Encrypted) {
`object`.encrypt(message.to!!.pubkey!!)
if (newObjectMessage.payload is Encrypted) {
newObjectMessage.encrypt(message.to!!.pubkey!!)
}
doProofOfWork(message.to, `object`)
doProofOfWork(message.to, newObjectMessage)
}
powRepo.removeObject(initialHash)
}

View File

@ -28,14 +28,14 @@ data class Addr constructor(val addresses: List<NetworkAddress>) : MessagePayloa
override val command: MessagePayload.Command = MessagePayload.Command.ADDR
override fun write(out: OutputStream) {
Encode.varInt(addresses.size.toLong(), out)
Encode.varInt(addresses.size, out)
for (address in addresses) {
address.write(out)
}
}
override fun write(buffer: ByteBuffer) {
Encode.varInt(addresses.size.toLong(), buffer)
Encode.varInt(addresses.size, buffer)
for (address in addresses) {
address.write(buffer)
}

View File

@ -29,14 +29,14 @@ class GetData constructor(var inventory: List<InventoryVector>) : MessagePayload
override val command: MessagePayload.Command = MessagePayload.Command.GETDATA
override fun write(out: OutputStream) {
Encode.varInt(inventory.size.toLong(), out)
Encode.varInt(inventory.size, out)
for (iv in inventory) {
iv.write(out)
}
}
override fun write(buffer: ByteBuffer) {
Encode.varInt(inventory.size.toLong(), buffer)
Encode.varInt(inventory.size, buffer)
for (iv in inventory) {
iv.write(buffer)
}

View File

@ -29,14 +29,14 @@ class Inv constructor(val inventory: List<InventoryVector>) : MessagePayload {
override val command: MessagePayload.Command = MessagePayload.Command.INV
override fun write(out: OutputStream) {
Encode.varInt(inventory.size.toLong(), out)
Encode.varInt(inventory.size, out)
for (iv in inventory) {
iv.write(out)
}
}
override fun write(buffer: ByteBuffer) {
Encode.varInt(inventory.size.toLong(), buffer)
Encode.varInt(inventory.size, buffer)
for (iv in inventory) {
iv.write(buffer)
}

View File

@ -43,7 +43,7 @@ data class NetworkMessage(
@Throws(IOException::class)
override fun write(out: OutputStream) {
// magic
Encode.int32(MAGIC.toLong(), out)
Encode.int32(MAGIC, out)
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
val command = payload.command.name.toLowerCase()
@ -57,7 +57,7 @@ data class NetworkMessage(
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
// larger than this.
Encode.int32(payloadBytes.size.toLong(), out)
Encode.int32(payloadBytes.size, out)
// checksum
out.write(getChecksum(payloadBytes))
@ -92,7 +92,7 @@ data class NetworkMessage(
private fun writeHeader(out: ByteBuffer): ByteArray {
// magic
Encode.int32(MAGIC.toLong(), out)
Encode.int32(MAGIC, out)
// ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected)
val command = payload.command.name.toLowerCase()
@ -107,7 +107,7 @@ data class NetworkMessage(
// Length of payload in number of bytes. Because of other restrictions, there is no reason why this length would
// ever be larger than 1600003 bytes. Some clients include a sanity-check to avoid processing messages which are
// larger than this.
Encode.int32(payloadBytes.size.toLong(), out)
Encode.int32(payloadBytes.size, out)
// checksum
out.put(getChecksum(payloadBytes))

View File

@ -17,6 +17,7 @@
package ch.dissem.bitmessage.entity
import ch.dissem.bitmessage.entity.Plaintext.Encoding.*
import ch.dissem.bitmessage.entity.Plaintext.Type.MSG
import ch.dissem.bitmessage.entity.payload.Msg
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature
import ch.dissem.bitmessage.entity.valueobject.ExtendedEncoding
@ -38,10 +39,20 @@ import kotlin.collections.HashSet
fun message(encoding: Plaintext.Encoding, subject: String, body: String): ByteArray = when (encoding) {
SIMPLE -> "Subject:$subject\nBody:$body".toByteArray()
EXTENDED -> Message.Builder().subject(subject).body(body).build().zip()
TRIVIAL -> (subject+body).toByteArray()
TRIVIAL -> (subject + body).toByteArray()
IGNORE -> ByteArray(0)
}
fun ackData(type: Plaintext.Type, ackData: ByteArray?): ByteArray? {
if (ackData != null) {
return ackData
} else if (type == MSG) {
return cryptography().randomBytes(Msg.ACK_LENGTH)
} else {
return null
}
}
/**
* The unencrypted message to be sent by 'msg' or 'broadcast'.
*/
@ -52,7 +63,7 @@ class Plaintext private constructor(
val encodingCode: Long,
val message: ByteArray,
val ackData: ByteArray?,
ackMessage: Lazy<ObjectMessage?>,
ackMessage: Lazy<ObjectMessage?> = lazy { Factory.createAck(from, ackData, ttl) },
val conversationId: UUID = UUID.randomUUID(),
var inventoryVector: InventoryVector? = null,
var signature: ByteArray? = null,
@ -121,7 +132,7 @@ class Plaintext private constructor(
to: BitmessageAddress?,
encoding: Encoding,
message: ByteArray,
ackData: ByteArray = cryptography().randomBytes(Msg.ACK_LENGTH),
ackData: ByteArray? = null,
conversationId: UUID = UUID.randomUUID(),
inventoryVector: InventoryVector? = null,
signature: ByteArray? = null,
@ -131,21 +142,20 @@ class Plaintext private constructor(
labels: MutableSet<Label> = HashSet(),
status: Status
) : this(
type,
from,
to,
encoding.code,
message,
ackData,
lazy { Factory.createAck(from, ackData, ttl) },
conversationId,
inventoryVector,
signature,
received,
initialHash,
ttl,
labels,
status
type = type,
from = from,
to = to,
encoding = encoding.code,
message = message,
ackMessage = ackData(type, ackData),
conversationId = conversationId,
inventoryVector = inventoryVector,
signature = signature,
received = received,
initialHash = initialHash,
ttl = ttl,
labels = labels,
status = status
)
constructor(
@ -164,13 +174,13 @@ class Plaintext private constructor(
labels: MutableSet<Label> = HashSet(),
status: Status
) : this(
type,
from,
to,
encoding,
message,
null,
lazy {
type = type,
from = from,
to = to,
encodingCode = encoding,
message = message,
ackData = null,
ackMessage = lazy {
if (ackMessage != null && ackMessage.isNotEmpty()) {
Factory.getObjectMessage(
3,
@ -178,14 +188,14 @@ class Plaintext private constructor(
ackMessage.size)
} else null
},
conversationId,
inventoryVector,
signature,
received,
initialHash,
ttl,
labels,
status
conversationId = conversationId,
inventoryVector = inventoryVector,
signature = signature,
received = received,
initialHash = initialHash,
ttl = ttl,
labels = labels,
status = status
)
constructor(
@ -195,37 +205,36 @@ class Plaintext private constructor(
encoding: Encoding = SIMPLE,
subject: String,
body: String,
ackData: ByteArray = cryptography().randomBytes(Msg.ACK_LENGTH),
ackData: ByteArray? = null,
conversationId: UUID = UUID.randomUUID(),
ttl: Long = TTL.msg,
labels: MutableSet<Label> = HashSet(),
status: Status = Status.DRAFT
) : this(
type,
from,
to,
encoding.code,
message(encoding, subject, body),
ackData,
lazy { Factory.createAck(from, ackData, ttl) },
conversationId,
null,
null,
null,
null,
ttl,
labels,
status
type = type,
from = from,
to = to,
encoding = encoding.code,
message = message(encoding, subject, body),
ackMessage = ackData(type, ackData),
conversationId = conversationId,
inventoryVector = null,
signature = null,
received = null,
initialHash = null,
ttl = ttl,
labels = labels,
status = status
)
constructor(builder: Builder) : this(
builder.type,
builder.from ?: throw IllegalStateException("sender identity not set"),
builder.to,
builder.encoding,
builder.message,
builder.ackData,
lazy {
type = builder.type,
from = builder.from ?: throw IllegalStateException("sender identity not set"),
to = builder.to,
encodingCode = builder.encoding,
message = builder.message,
ackData = builder.ackData,
ackMessage = lazy {
val ackMsg = builder.ackMessage
if (ackMsg != null && ackMsg.isNotEmpty()) {
Factory.getObjectMessage(
@ -236,15 +245,17 @@ class Plaintext private constructor(
Factory.createAck(builder.from!!, builder.ackData, builder.ttl)
}
},
builder.conversation ?: UUID.randomUUID(),
builder.inventoryVector,
builder.signature,
builder.received,
null,
builder.ttl,
builder.labels,
builder.status ?: Status.RECEIVED
)
conversationId = builder.conversation ?: UUID.randomUUID(),
inventoryVector = builder.inventoryVector,
signature = builder.signature,
received = builder.received,
initialHash = null,
ttl = builder.ttl,
labels = builder.labels,
status = builder.status ?: Status.RECEIVED
) {
id = builder.id
}
fun write(out: OutputStream, includeSignature: Boolean) {
Encode.varInt(from.version, out)
@ -259,7 +270,7 @@ class Plaintext private constructor(
Encode.varInt(0, out)
}
} else {
Encode.int32(from.pubkey!!.behaviorBitfield.toLong(), out)
Encode.int32(from.pubkey!!.behaviorBitfield, out)
out.write(from.pubkey!!.signingKey, 1, 64)
out.write(from.pubkey!!.encryptionKey, 1, 64)
if (from.version >= 3) {
@ -267,13 +278,13 @@ class Plaintext private constructor(
Encode.varInt(from.pubkey!!.extraBytes, out)
}
}
if (type == Type.MSG) {
if (type == MSG) {
out.write(to!!.ripe)
}
Encode.varInt(encodingCode, out)
Encode.varInt(message.size.toLong(), out)
Encode.varInt(message.size, out)
out.write(message)
if (type == Type.MSG) {
if (type == MSG) {
if (to?.has(Feature.DOES_ACK) ?: false) {
val ack = ByteArrayOutputStream()
ackMessage?.write(ack)
@ -286,8 +297,7 @@ class Plaintext private constructor(
if (signature == null) {
Encode.varInt(0, out)
} else {
Encode.varInt(signature!!.size.toLong(), out)
out.write(signature!!)
Encode.varBytes(signature!!, out)
}
}
}
@ -305,7 +315,7 @@ class Plaintext private constructor(
Encode.varInt(0, buffer)
}
} else {
Encode.int32(from.pubkey!!.behaviorBitfield.toLong(), buffer)
Encode.int32(from.pubkey!!.behaviorBitfield, buffer)
buffer.put(from.pubkey!!.signingKey, 1, 64)
buffer.put(from.pubkey!!.encryptionKey, 1, 64)
if (from.version >= 3) {
@ -313,13 +323,12 @@ class Plaintext private constructor(
Encode.varInt(from.pubkey!!.extraBytes, buffer)
}
}
if (type == Type.MSG) {
if (type == MSG) {
buffer.put(to!!.ripe)
}
Encode.varInt(encodingCode, buffer)
Encode.varInt(message.size.toLong(), buffer)
buffer.put(message)
if (type == Type.MSG) {
Encode.varBytes(message, buffer)
if (type == MSG) {
if (to!!.has(Feature.DOES_ACK) && ackMessage != null) {
Encode.varBytes(Encode.bytes(ackMessage!!), buffer)
} else {
@ -331,8 +340,7 @@ class Plaintext private constructor(
if (sig == null) {
Encode.varInt(0, buffer)
} else {
Encode.varInt(sig.size.toLong(), buffer)
buffer.put(sig)
Encode.varBytes(sig, buffer)
}
}
}
@ -365,7 +373,7 @@ class Plaintext private constructor(
val firstLine = s.nextLine()
if (encodingCode == EXTENDED.code) {
if (Message.TYPE == extendedData?.type) {
return (extendedData!!.content as Message?)?.subject
return (extendedData!!.content as? Message)?.subject
} else {
return null
}
@ -551,10 +559,12 @@ class Plaintext private constructor(
return this
}
fun to(address: BitmessageAddress): Builder {
if (type != Type.MSG && to != null)
throw IllegalArgumentException("recipient address only allowed for msg")
to = address
fun to(address: BitmessageAddress?): Builder {
if (address != null) {
if (type != MSG && to != null)
throw IllegalArgumentException("recipient address only allowed for msg")
to = address
}
return this
}
@ -594,7 +604,7 @@ class Plaintext private constructor(
}
fun destinationRipe(ripe: ByteArray?): Builder {
if (type != Type.MSG && ripe != null) throw IllegalArgumentException("ripe only allowed for msg")
if (type != MSG && ripe != null) throw IllegalArgumentException("ripe only allowed for msg")
this.destinationRipe = ripe
return this
}
@ -622,7 +632,6 @@ class Plaintext private constructor(
} catch (e: UnsupportedEncodingException) {
throw ApplicationException(e)
}
return this
}
@ -632,13 +641,13 @@ class Plaintext private constructor(
}
fun ackMessage(ack: ByteArray?): Builder {
if (type != Type.MSG && ack != null) throw IllegalArgumentException("ackMessage only allowed for msg")
if (type != MSG && ack != null) throw IllegalArgumentException("ackMessage only allowed for msg")
this.ackMessage = ack
return this
}
fun ackData(ackData: ByteArray?): Builder {
if (type != Type.MSG && ackData != null)
if (type != MSG && ackData != null)
throw IllegalArgumentException("ackMessage only allowed for msg")
this.ackData = ackData
return this
@ -704,7 +713,7 @@ class Plaintext private constructor(
if (to == null && type != Type.BROADCAST && destinationRipe != null) {
to = BitmessageAddress(0, 0, destinationRipe!!)
}
if (type == Type.MSG && ackMessage == null && ackData == null) {
if (type == MSG && ackMessage == null && ackData == null) {
ackData = cryptography().randomBytes(Msg.ACK_LENGTH)
}
if (ttl <= 0) {
@ -733,10 +742,10 @@ class Plaintext private constructor(
.publicEncryptionKey(Decode.bytes(`in`, 64))
.nonceTrialsPerByte(if (version >= 3) Decode.varInt(`in`) else 0)
.extraBytes(if (version >= 3) Decode.varInt(`in`) else 0)
.destinationRipe(if (type == Type.MSG) Decode.bytes(`in`, 20) else null)
.destinationRipe(if (type == MSG) Decode.bytes(`in`, 20) else null)
.encoding(Decode.varInt(`in`))
.message(Decode.varBytes(`in`))
.ackMessage(if (type == Type.MSG) Decode.varBytes(`in`) else null)
.ackMessage(if (type == MSG) Decode.varBytes(`in`) else null)
}
}
}

View File

@ -78,7 +78,7 @@ class Version constructor(
override val command: MessagePayload.Command = MessagePayload.Command.VERSION
override fun write(out: OutputStream) {
Encode.int32(version.toLong(), out)
Encode.int32(version, out)
Encode.int64(services, out)
Encode.int64(timestamp, out)
addrRecv.write(out, true)
@ -89,7 +89,7 @@ class Version constructor(
}
override fun write(buffer: ByteBuffer) {
Encode.int32(version.toLong(), buffer)
Encode.int32(version, buffer)
Encode.int64(services, buffer)
Encode.int64(timestamp, buffer)
addrRecv.write(buffer, true)

View File

@ -114,7 +114,7 @@ class CryptoBox : Streamable {
private fun writeWithoutMAC(out: OutputStream) {
out.write(initializationVector)
Encode.int16(curveType.toLong(), out)
Encode.int16(curveType, out)
writeCoordinateComponent(out, Points.getX(R))
writeCoordinateComponent(out, Points.getY(R))
out.write(encrypted)
@ -123,14 +123,14 @@ class CryptoBox : Streamable {
private fun writeCoordinateComponent(out: OutputStream, x: ByteArray) {
val offset = Bytes.numberOfLeadingZeros(x)
val length = x.size - offset
Encode.int16(length.toLong(), out)
Encode.int16(length, out)
out.write(x, offset, length)
}
private fun writeCoordinateComponent(buffer: ByteBuffer, x: ByteArray) {
val offset = Bytes.numberOfLeadingZeros(x)
val length = x.size - offset
Encode.int16(length.toLong(), buffer)
Encode.int16(length, buffer)
buffer.put(x, offset, length)
}
@ -141,7 +141,7 @@ class CryptoBox : Streamable {
override fun write(buffer: ByteBuffer) {
buffer.put(initializationVector)
Encode.int16(curveType.toLong(), buffer)
Encode.int16(curveType, buffer)
writeCoordinateComponent(buffer, Points.getX(R))
writeCoordinateComponent(buffer, Points.getY(R))
buffer.put(encrypted)

View File

@ -31,13 +31,13 @@ open class V2Pubkey constructor(version: Long, override val stream: Long, overri
override val encryptionKey: ByteArray = if (encryptionKey.size == 64) add0x04(encryptionKey) else encryptionKey
override fun write(out: OutputStream) {
Encode.int32(behaviorBitfield.toLong(), out)
Encode.int32(behaviorBitfield, out)
out.write(signingKey, 1, 64)
out.write(encryptionKey, 1, 64)
}
override fun write(buffer: ByteBuffer) {
Encode.int32(behaviorBitfield.toLong(), buffer)
Encode.int32(behaviorBitfield, buffer)
buffer.put(signingKey, 1, 64)
buffer.put(encryptionKey, 1, 64)
}

View File

@ -19,11 +19,14 @@ package ch.dissem.bitmessage.entity.valueobject
import java.io.Serializable
import java.util.*
data class Label(private val label: String, val type: Label.Type,
/**
* RGBA representation for the color.
*/
var color: Int) : Serializable {
data class Label(
private val label: String,
val type: Label.Type?,
/**
* RGBA representation for the color.
*/
var color: Int
) : Serializable {
var id: Any? = null

View File

@ -30,7 +30,7 @@ import java.util.*
/**
* A node's address. It's written in IPv6 format.
*/
data class NetworkAddress constructor(
data class NetworkAddress(
var time: Long,
/**
@ -47,25 +47,25 @@ data class NetworkAddress constructor(
* IPv6 address. IPv4 addresses are written into the message as a 16 byte IPv4-mapped IPv6 address
* (12 bytes 00 00 00 00 00 00 00 00 00 00 FF FF, followed by the 4 bytes of the IPv4 address).
*/
val iPv6: ByteArray,
val IPv6: ByteArray,
val port: Int
) : Streamable {
fun provides(service: Version.Service?): Boolean = service?.isEnabled(services) ?: false
fun toInetAddress(): InetAddress {
return InetAddress.getByAddress(iPv6)
return InetAddress.getByAddress(IPv6)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is NetworkAddress) return false
return port == other.port && Arrays.equals(iPv6, other.iPv6)
return port == other.port && Arrays.equals(IPv6, other.IPv6)
}
override fun hashCode(): Int {
var result = Arrays.hashCode(iPv6)
var result = Arrays.hashCode(IPv6)
result = 31 * result + port
return result
}
@ -84,8 +84,8 @@ data class NetworkAddress constructor(
Encode.int32(stream, out)
}
Encode.int64(services, out)
out.write(iPv6)
Encode.int16(port.toLong(), out)
out.write(IPv6)
Encode.int16(port, out)
}
override fun write(buffer: ByteBuffer) {
@ -98,8 +98,8 @@ data class NetworkAddress constructor(
Encode.int32(stream, buffer)
}
Encode.int64(services, buffer)
buffer.put(iPv6)
Encode.int16(port.toLong(), buffer)
buffer.put(IPv6)
Encode.int16(port, buffer)
}
class Builder {

View File

@ -121,12 +121,10 @@ class PrivateKey : Streamable {
Encode.varInt(pubkey.stream, out)
val baos = ByteArrayOutputStream()
pubkey.writeUnencrypted(baos)
Encode.varInt(baos.size().toLong(), out)
Encode.varInt(baos.size(), out)
out.write(baos.toByteArray())
Encode.varInt(privateSigningKey.size.toLong(), out)
out.write(privateSigningKey)
Encode.varInt(privateEncryptionKey.size.toLong(), out)
out.write(privateEncryptionKey)
Encode.varBytes(privateSigningKey, out)
Encode.varBytes(privateEncryptionKey, out)
}

View File

@ -37,7 +37,7 @@ import javax.crypto.spec.SecretKeySpec
* Implements everything that isn't directly dependent on either Spongy- or Bouncycastle.
*/
abstract class AbstractCryptography protected constructor(@JvmField protected val provider: Provider) : Cryptography {
private val context by InternalContext
private val context by InternalContext.lateinit
@JvmField protected val ALGORITHM_ECDSA = "ECDSA"
@JvmField protected val ALGORITHM_ECDSA_SHA1 = "SHA1withECDSA"
@ -87,21 +87,21 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va
return result
}
override fun doProofOfWork(`object`: ObjectMessage, nonceTrialsPerByte: Long,
override fun doProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long,
extraBytes: Long, callback: ProofOfWorkEngine.Callback) {
val initialHash = getInitialHash(`object`)
val initialHash = getInitialHash(objectMessage)
val target = getProofOfWorkTarget(`object`,
val target = getProofOfWorkTarget(objectMessage,
max(nonceTrialsPerByte, NETWORK_NONCE_TRIALS_PER_BYTE), max(extraBytes, NETWORK_EXTRA_BYTES))
context.proofOfWorkEngine.calculateNonce(initialHash, target, callback)
}
@Throws(InsufficientProofOfWorkException::class)
override fun checkProofOfWork(`object`: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long) {
val target = getProofOfWorkTarget(`object`, nonceTrialsPerByte, extraBytes)
val value = doubleSha512(`object`.nonce ?: throw ApplicationException("Object without nonce"), getInitialHash(`object`))
override fun checkProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long) {
val target = getProofOfWorkTarget(objectMessage, nonceTrialsPerByte, extraBytes)
val value = doubleSha512(objectMessage.nonce ?: throw ApplicationException("Object without nonce"), getInitialHash(objectMessage))
if (Bytes.lt(target, value, 8)) {
throw InsufficientProofOfWorkException(target, value)
}
@ -130,18 +130,18 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va
return false
}
override fun getInitialHash(`object`: ObjectMessage): ByteArray {
return sha512(`object`.payloadBytesWithoutNonce)
override fun getInitialHash(objectMessage: ObjectMessage): ByteArray {
return sha512(objectMessage.payloadBytesWithoutNonce)
}
override fun getProofOfWorkTarget(`object`: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long): ByteArray {
override fun getProofOfWorkTarget(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long): ByteArray {
@Suppress("NAME_SHADOWING")
val nonceTrialsPerByte = if (nonceTrialsPerByte == 0L) NETWORK_NONCE_TRIALS_PER_BYTE else nonceTrialsPerByte
@Suppress("NAME_SHADOWING")
val extraBytes = if (extraBytes == 0L) NETWORK_EXTRA_BYTES else extraBytes
val TTL = BigInteger.valueOf(`object`.expiresTime - UnixTime.now)
val powLength = BigInteger.valueOf(`object`.payloadBytesWithoutNonce.size + extraBytes)
val TTL = BigInteger.valueOf(objectMessage.expiresTime - UnixTime.now)
val powLength = BigInteger.valueOf(objectMessage.payloadBytesWithoutNonce.size + extraBytes)
val denominator = BigInteger.valueOf(nonceTrialsPerByte)
.multiply(
powLength.add(

View File

@ -28,19 +28,19 @@ import ch.dissem.bitmessage.utils.UnixTime
import java.util.*
abstract class AbstractMessageRepository : MessageRepository {
protected var ctx by InternalContext
protected var ctx by InternalContext.lateinit
protected fun saveContactIfNecessary(contact: BitmessageAddress?) {
contact?.let {
val savedAddress = ctx.addressRepository.getAddress(contact.address)
val savedAddress = ctx.addressRepository.getAddress(it.address)
if (savedAddress == null) {
ctx.addressRepository.save(contact)
} else if (savedAddress.pubkey == null && contact.pubkey != null) {
savedAddress.pubkey = contact.pubkey
ctx.addressRepository.save(savedAddress)
}
if (savedAddress != null) {
contact.alias = savedAddress.alias
ctx.addressRepository.save(it)
} else {
if (savedAddress.pubkey == null && it.pubkey != null) {
savedAddress.pubkey = it.pubkey
ctx.addressRepository.save(savedAddress)
}
it.alias = savedAddress.alias
}
}
}

View File

@ -145,7 +145,7 @@ interface Cryptography {
* Calculates the proof of work. This might take a long time, depending on the hardware, message size and time to
* live.
* @param object to do the proof of work for
* @param objectMessage to do the proof of work for
* *
* @param nonceTrialsPerByte difficulty
* *
@ -153,11 +153,11 @@ interface Cryptography {
* *
* @param callback to handle nonce once it's calculated
*/
fun doProofOfWork(`object`: ObjectMessage, nonceTrialsPerByte: Long,
fun doProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long,
extraBytes: Long, callback: ProofOfWorkEngine.Callback)
/**
* @param object to be checked
* @param objectMessage to be checked
* *
* @param nonceTrialsPerByte difficulty
* *
@ -166,11 +166,11 @@ interface Cryptography {
* @throws InsufficientProofOfWorkException if proof of work doesn't check out (makes it more difficult to send small messages)
*/
@Throws(InsufficientProofOfWorkException::class)
fun checkProofOfWork(`object`: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long)
fun checkProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long)
fun getInitialHash(`object`: ObjectMessage): ByteArray
fun getInitialHash(objectMessage: ObjectMessage): ByteArray
fun getProofOfWorkTarget(`object`: ObjectMessage, nonceTrialsPerByte: Long = NETWORK_NONCE_TRIALS_PER_BYTE, extraBytes: Long = NETWORK_EXTRA_BYTES): ByteArray
fun getProofOfWorkTarget(objectMessage: ObjectMessage, nonceTrialsPerByte: Long = NETWORK_NONCE_TRIALS_PER_BYTE, extraBytes: Long = NETWORK_EXTRA_BYTES): ByteArray
/**
* Calculates the MAC for a message (data)

View File

@ -23,7 +23,7 @@ import ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST
import ch.dissem.bitmessage.entity.valueobject.Label
open class DefaultLabeler : Labeler {
private var ctx by InternalContext
private var ctx by InternalContext.lateinit
override fun setLabels(msg: Plaintext) {
msg.status = RECEIVED

View File

@ -43,9 +43,9 @@ interface Inventory {
*/
fun getObjects(stream: Long, version: Long, vararg types: ObjectType): List<ObjectMessage>
fun storeObject(`object`: ObjectMessage)
fun storeObject(objectMessage: ObjectMessage)
operator fun contains(`object`: ObjectMessage): Boolean
operator fun contains(objectMessage: ObjectMessage): Boolean
/**
* Deletes all objects that expired 5 minutes ago or earlier

View File

@ -28,7 +28,7 @@ interface MessageRepository {
fun getLabels(vararg types: Label.Type): List<Label>
fun countUnread(label: Label): Int
fun countUnread(label: Label?): Int
fun getMessage(id: Any): Plaintext
@ -43,7 +43,7 @@ interface MessageRepository {
* *
* @return a distinct list of all conversations that have at least one message with the given label.
*/
fun findConversations(label: Label): List<UUID>
fun findConversations(label: Label?): List<UUID>
fun findMessages(label: Label?): List<Plaintext>

View File

@ -81,6 +81,6 @@ interface NetworkHandler {
interface MessageListener {
@Throws(IOException::class)
fun receive(`object`: ObjectMessage)
fun receive(objectMessage: ObjectMessage)
}
}

View File

@ -29,14 +29,14 @@ interface ProofOfWorkRepository {
fun getItems(): List<ByteArray>
fun putObject(`object`: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long)
fun putObject(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long)
fun putObject(item: Item)
fun removeObject(initialHash: ByteArray)
data class Item @JvmOverloads constructor(
val `object`: ObjectMessage,
val objectMessage: ObjectMessage,
val nonceTrialsPerByte: Long,
val extraBytes: Long,
// Needed for ACK POW calculation

View File

@ -19,6 +19,7 @@ package ch.dissem.bitmessage.utils
import ch.dissem.bitmessage.entity.Plaintext
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
import ch.dissem.bitmessage.ports.MessageRepository
import org.slf4j.LoggerFactory
import java.util.*
import java.util.Collections
import java.util.regex.Pattern

View File

@ -27,19 +27,20 @@ import java.nio.ByteBuffer
*/
object Encode {
@JvmStatic fun varIntList(values: LongArray, stream: OutputStream) {
varInt(values.size.toLong(), stream)
varInt(values.size, stream)
for (value in values) {
varInt(value, stream)
}
}
@JvmStatic fun varIntList(values: LongArray, buffer: ByteBuffer) {
varInt(values.size.toLong(), buffer)
varInt(values.size, buffer)
for (value in values) {
varInt(value, buffer)
}
}
@JvmStatic fun varInt(value: Int, buffer: ByteBuffer) = varInt(value.toLong(), buffer)
@JvmStatic fun varInt(value: Long, buffer: ByteBuffer) {
if (value < 0) {
// This is due to the fact that Java doesn't really support unsigned values.
@ -62,6 +63,7 @@ object Encode {
}
}
@JvmStatic fun varInt(value: Int) = varInt(value.toLong())
@JvmStatic fun varInt(value: Long): ByteArray {
val buffer = ByteBuffer.allocate(9)
varInt(value, buffer)
@ -69,6 +71,7 @@ object Encode {
return Bytes.truncate(buffer.array(), buffer.limit())
}
@JvmStatic @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)
varInt(value, buffer)
@ -77,27 +80,34 @@ object Encode {
AccessCounter.inc(counter, buffer.limit())
}
@JvmStatic @JvmOverloads fun int8(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
stream.write(value.toInt())
@JvmStatic @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)
AccessCounter.inc(counter)
}
@JvmStatic @JvmOverloads fun int16(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
stream.write(ByteBuffer.allocate(2).putShort(value.toShort()).array())
@JvmStatic @JvmOverloads 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())
AccessCounter.inc(counter, 2)
}
@JvmStatic fun int16(value: Long, buffer: ByteBuffer) {
buffer.putShort(value.toShort())
@JvmStatic fun int16(value: Long, buffer: ByteBuffer) = int16(value.toShort(), buffer)
@JvmStatic fun int16(value: Int, buffer: ByteBuffer) = int16(value.toShort(), buffer)
@JvmStatic fun int16(value: Short, buffer: ByteBuffer) {
buffer.putShort(value)
}
@JvmStatic @JvmOverloads fun int32(value: Long, stream: OutputStream, counter: AccessCounter? = null) {
stream.write(ByteBuffer.allocate(4).putInt(value.toInt()).array())
@JvmStatic @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())
AccessCounter.inc(counter, 4)
}
@JvmStatic fun int32(value: Long, buffer: ByteBuffer) {
buffer.putInt(value.toInt())
@JvmStatic fun int32(value: Long, buffer: ByteBuffer) = int32(value.toInt(), buffer)
@JvmStatic fun int32(value: Int, buffer: ByteBuffer) {
buffer.putInt(value)
}
@JvmStatic @JvmOverloads fun int64(value: Long, stream: OutputStream, counter: AccessCounter? = null) {

View File

@ -28,8 +28,8 @@ import ch.dissem.bitmessage.ports.DefaultLabeler
import ch.dissem.bitmessage.ports.ProofOfWorkEngine
import ch.dissem.bitmessage.ports.ProofOfWorkRepository
import ch.dissem.bitmessage.testutils.TestInventory
import ch.dissem.bitmessage.utils.Singleton
import ch.dissem.bitmessage.utils.Singleton.cryptography
import ch.dissem.bitmessage.utils.Strings.hex
import ch.dissem.bitmessage.utils.TTL
import ch.dissem.bitmessage.utils.TestUtils
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
@ -40,12 +40,12 @@ import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import java.util.*
import kotlin.concurrent.thread
/**
* @author Christian Basler
*/
class BitmessageContextTest {
private lateinit var ctx: BitmessageContext
private var listener: BitmessageContext.Listener = mock()
private val inventory = spy(TestInventory())
private val testPowRepo = spy(object : ProofOfWorkRepository {
@ -54,7 +54,7 @@ class BitmessageContextTest {
internal var removed = 0
override fun getItem(initialHash: ByteArray): ProofOfWorkRepository.Item {
return items[InventoryVector(initialHash)]!!
return items[InventoryVector(initialHash)] ?: throw IllegalArgumentException("${hex(initialHash)} not found in $items")
}
override fun getItems(): List<ByteArray> {
@ -66,12 +66,12 @@ class BitmessageContextTest {
}
override fun putObject(item: ProofOfWorkRepository.Item) {
items.put(InventoryVector(cryptography().getInitialHash(item.`object`)), item)
items.put(InventoryVector(cryptography().getInitialHash(item.objectMessage)), item)
added++
}
override fun putObject(`object`: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long) {
items.put(InventoryVector(cryptography().getInitialHash(`object`)), ProofOfWorkRepository.Item(`object`, nonceTrialsPerByte, extraBytes))
override fun putObject(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long) {
items.put(InventoryVector(cryptography().getInitialHash(objectMessage)), ProofOfWorkRepository.Item(objectMessage, nonceTrialsPerByte, extraBytes))
added++
}
@ -87,39 +87,42 @@ class BitmessageContextTest {
removed = 0
}
})
private val testPowEngine = spy(object : ProofOfWorkEngine {
override fun calculateNonce(initialHash: ByteArray, target: ByteArray, callback: ProofOfWorkEngine.Callback) {
thread { callback.onNonceCalculated(initialHash, ByteArray(8)) }
}
})
private var ctx = BitmessageContext.Builder()
.addressRepo(mock())
.cryptography(BouncyCryptography())
.inventory(inventory)
.listener(listener)
.messageRepo(mock())
.networkHandler(mock())
.nodeRegistry(mock())
.labeler(spy(DefaultLabeler()))
.powRepo(testPowRepo)
.proofOfWorkEngine(testPowEngine)
.build()
init {
TTL.msg = 2 * MINUTE
}
@Before
fun setUp() {
Singleton.initialize(BouncyCryptography())
ctx = BitmessageContext.Builder()
.addressRepo(mock())
.cryptography(cryptography())
.inventory(inventory)
.listener(listener)
.messageRepo(mock())
.networkHandler(mock())
.nodeRegistry(mock())
.labeler(spy(DefaultLabeler()))
.powRepo(testPowRepo)
.proofOfWorkEngine(spy(object : ProofOfWorkEngine {
override fun calculateNonce(initialHash: ByteArray, target: ByteArray, callback: ProofOfWorkEngine.Callback) {
callback.onNonceCalculated(initialHash, ByteArray(8))
}
}))
.build()
TTL.msg = 2 * MINUTE
testPowRepo.reset()
}
@Test
fun `ensure contact is saved and pubkey requested`() {
val contact = BitmessageAddress("BM-opWQhvk9xtMFvQA2Kvetedpk8LkbraWHT")
whenever(ctx.addresses.getAddress(contact.address)).thenReturn(contact)
doReturn(contact).whenever(ctx.addresses).getAddress(eq(contact.address))
ctx.addContact(contact)
verify(ctx.addresses, timeout(1000).atLeastOnce()).save(contact)
verify(ctx.internals.proofOfWorkEngine, timeout(1000)).calculateNonce(any(), any(), any())
verify(ctx.addresses, timeout(1000).atLeastOnce()).save(eq(contact))
verify(testPowEngine, timeout(1000)).calculateNonce(any(), any(), any())
}
@Test
@ -132,7 +135,7 @@ class BitmessageContextTest {
ctx.addContact(contact)
verify(ctx.addresses, times(1)).save(contact)
verify(ctx.internals.proofOfWorkEngine, never()).calculateNonce(any(), any(), any())
verify(testPowEngine, never()).calculateNonce(any(), any(), any())
}
@Test
@ -155,7 +158,7 @@ class BitmessageContextTest {
ctx.addContact(contact)
verify(ctx.addresses, atLeastOnce()).save(contact)
verify(ctx.internals.proofOfWorkEngine, never()).calculateNonce(any(), any(), any())
verify(testPowEngine, never()).calculateNonce(any(), any(), any())
}
@Test
@ -179,7 +182,7 @@ class BitmessageContextTest {
ctx.addContact(contact)
verify(ctx.addresses, atLeastOnce()).save(any())
verify(ctx.internals.proofOfWorkEngine, never()).calculateNonce(any(), any(), any())
verify(testPowEngine, never()).calculateNonce(any(), any(), any())
}
@Test
@ -209,9 +212,9 @@ class BitmessageContextTest {
fun `ensure message is sent`() {
ctx.send(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"), TestUtils.loadContact(),
"Subject", "Message")
verify(ctx.internals.proofOfWorkRepository, timeout(10000)).putObject(
argThat { payload.type == ObjectType.MSG }, eq(1000L), eq(1000L))
assertEquals(2, testPowRepo.added)
verify(ctx.internals.proofOfWorkRepository, timeout(10000).atLeastOnce())
.putObject(argThat { payload.type == ObjectType.MSG }, eq(1000L), eq(1000L))
verify(ctx.messages, timeout(10000).atLeastOnce()).save(argThat { type == Type.MSG })
}
@ -236,10 +239,9 @@ class BitmessageContextTest {
fun `ensure broadcast is sent`() {
ctx.broadcast(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"),
"Subject", "Message")
verify(ctx.internals.proofOfWorkRepository, timeout(10000).atLeastOnce())
verify(ctx.internals.proofOfWorkRepository, timeout(1000).atLeastOnce())
.putObject(argThat { payload.type == ObjectType.BROADCAST }, eq(1000L), eq(1000L))
verify(ctx.internals.proofOfWorkEngine)
.calculateNonce(any(), any(), any())
verify(testPowEngine).calculateNonce(any(), any(), any())
verify(ctx.messages, timeout(10000).atLeastOnce()).save(argThat { type == Type.BROADCAST })
}
@ -265,7 +267,7 @@ class BitmessageContextTest {
fun `ensure deterministic addresses are created`() {
val expected_size = 8
val addresses = ctx.createDeterministicAddresses("test", expected_size, 4, 1, false)
assertEquals(expected_size.toLong(), addresses.size.toLong())
assertEquals(expected_size, addresses.size)
val expected = HashSet<String>(expected_size)
expected.add("BM-2cWFkyuXXFw6d393RGnin2RpSXj8wxtt6F")
expected.add("BM-2cX8TF9vuQZEWvT7UrEeq1HN9dgiSUPLEN")
@ -285,7 +287,7 @@ class BitmessageContextTest {
fun `ensure short deterministic addresses are created`() {
val expected_size = 1
val addresses = ctx.createDeterministicAddresses("test", expected_size, 4, 1, true)
assertEquals(expected_size.toLong(), addresses.size.toLong())
assertEquals(expected_size, addresses.size)
val expected = HashSet<String>(expected_size)
expected.add("BM-NBGyBAEp6VnBkFWKpzUSgxuTqVdWPi78")
for (a in addresses) {

View File

@ -16,6 +16,7 @@
package ch.dissem.bitmessage
import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography
import ch.dissem.bitmessage.entity.BitmessageAddress
import ch.dissem.bitmessage.entity.ObjectMessage
import ch.dissem.bitmessage.entity.Plaintext
@ -26,9 +27,12 @@ import ch.dissem.bitmessage.entity.payload.GetPubkey
import ch.dissem.bitmessage.entity.payload.Msg
import ch.dissem.bitmessage.entity.payload.ObjectType
import ch.dissem.bitmessage.factory.Factory
import ch.dissem.bitmessage.ports.ProofOfWorkRepository
import ch.dissem.bitmessage.utils.Singleton
import ch.dissem.bitmessage.utils.TestBase
import ch.dissem.bitmessage.utils.TestUtils
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
import ch.dissem.bitmessage.utils.UnixTime.now
import com.nhaarman.mockito_kotlin.*
import org.junit.Before
import org.junit.Test
@ -40,7 +44,7 @@ class DefaultMessageListenerTest : TestBase() {
private lateinit var listener: DefaultMessageListener
private val ctx = TestUtils.mockedInternalContext(
cryptography = Singleton.cryptography()
cryptography = BouncyCryptography()
)
@Before
@ -52,10 +56,13 @@ class DefaultMessageListenerTest : TestBase() {
fun `ensure pubkey is sent on request`() {
val identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")
whenever(ctx.addressRepository.findIdentity(any())).thenReturn(identity)
listener.receive(ObjectMessage.Builder()
.stream(2)
.payload(GetPubkey(BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")))
.build())
val objectMessage = ObjectMessage(
stream = 2,
payload = GetPubkey(BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")),
expiresTime = now + MINUTE
)
whenever(ctx.proofOfWorkRepository.getItem(any())).thenReturn(ProofOfWorkRepository.Item(objectMessage, 1000L, 1000L))
listener.receive(objectMessage)
verify(ctx.proofOfWorkRepository).putObject(argThat { type == ObjectType.PUBKEY.number }, any(), any())
}
@ -73,6 +80,7 @@ class DefaultMessageListenerTest : TestBase() {
.build()
objectMessage.sign(identity.privateKey!!)
objectMessage.encrypt(Singleton.cryptography().createPublicKey(identity.publicDecryptionKey))
whenever(ctx.proofOfWorkRepository.getItem(any())).thenReturn(ProofOfWorkRepository.Item(objectMessage, 1000L, 1000L))
listener.receive(objectMessage)
verify(ctx.addressRepository).save(eq(contact))

View File

@ -77,24 +77,24 @@ class ProofOfWorkServiceTest {
val identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")
val address = TestUtils.loadContact()
val plaintext = Plaintext.Builder(MSG).from(identity).to(address).message("", "").build()
val `object` = ObjectMessage(
val objectMessage = ObjectMessage(
expiresTime = 0,
stream = 1,
payload = Msg(plaintext)
)
`object`.sign(identity.privateKey!!)
`object`.encrypt(address.pubkey!!)
objectMessage.sign(identity.privateKey!!)
objectMessage.encrypt(address.pubkey!!)
val initialHash = ByteArray(64)
val nonce = byteArrayOf(1, 2, 3, 4, 5, 6, 7, 8)
whenever(ctx.proofOfWorkRepository.getItem(initialHash)).thenReturn(ProofOfWorkRepository.Item(`object`, 1001, 1002))
whenever(ctx.proofOfWorkRepository.getItem(initialHash)).thenReturn(ProofOfWorkRepository.Item(objectMessage, 1001, 1002))
whenever(ctx.messageRepository.getMessage(initialHash)).thenReturn(plaintext)
ctx.proofOfWorkService.onNonceCalculated(initialHash, nonce)
verify(ctx.proofOfWorkRepository).removeObject(eq(initialHash))
verify(ctx.inventory).storeObject(eq(`object`))
verify(ctx.networkHandler).offer(eq(`object`.inventoryVector))
assertThat(plaintext.inventoryVector, equalTo(`object`.inventoryVector))
verify(ctx.inventory).storeObject(eq(objectMessage))
verify(ctx.networkHandler).offer(eq(objectMessage.inventoryVector))
assertThat(plaintext.inventoryVector, equalTo(objectMessage.inventoryVector))
}
}

View File

@ -29,9 +29,9 @@ import org.junit.Test
class SignatureTest : TestBase() {
@Test
fun `ensure validation works`() {
val `object` = TestUtils.loadObjectMessage(3, "V3Pubkey.payload")
val pubkey = `object`.payload as Pubkey
assertTrue(`object`.isSignatureValid(pubkey))
val objectMessage = TestUtils.loadObjectMessage(3, "V3Pubkey.payload")
val pubkey = objectMessage.payload as Pubkey
assertTrue(objectMessage.isSignatureValid(pubkey))
}
@Test
@ -52,11 +52,11 @@ class SignatureTest : TestBase() {
fun `ensure message is properly signed`() {
val identity = TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")
val `object` = TestUtils.loadObjectMessage(3, "V1Msg.payload")
val msg = `object`.payload as Msg
val objectMessage = TestUtils.loadObjectMessage(3, "V1Msg.payload")
val msg = objectMessage.payload as Msg
msg.decrypt(identity.privateKey!!.privateEncryptionKey)
assertNotNull(msg.plaintext)
assertEquals(TestUtils.loadContact().pubkey, msg.plaintext!!.from.pubkey)
assertTrue(`object`.isSignatureValid(msg.plaintext!!.from.pubkey!!))
assertTrue(objectMessage.isSignatureValid(msg.plaintext!!.from.pubkey!!))
}
}

View File

@ -31,9 +31,9 @@ import java.util.*
class BitmessageAddressTest : TestBase() {
@Test
fun `ensure feature flag is calculated correctly`() {
Assert.assertEquals(1, Pubkey.Feature.bitfield(DOES_ACK).toLong())
assertEquals(2, Pubkey.Feature.bitfield(INCLUDE_DESTINATION).toLong())
assertEquals(3, Pubkey.Feature.bitfield(DOES_ACK, INCLUDE_DESTINATION).toLong())
Assert.assertEquals(1, Pubkey.Feature.bitfield(DOES_ACK))
assertEquals(2, Pubkey.Feature.bitfield(INCLUDE_DESTINATION))
assertEquals(3, Pubkey.Feature.bitfield(DOES_ACK, INCLUDE_DESTINATION))
}
@Test
@ -84,9 +84,9 @@ class BitmessageAddressTest : TestBase() {
val address = BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ")
Assert.assertArrayEquals(Bytes.fromHex("007402be6e76c3cb87caa946d0c003a3d4d8e1d5"), address.ripe)
val `object` = TestUtils.loadObjectMessage(3, "V3Pubkey.payload")
val pubkey = `object`.payload as Pubkey
assertTrue(`object`.isSignatureValid(pubkey))
val objectMessage = TestUtils.loadObjectMessage(3, "V3Pubkey.payload")
val pubkey = objectMessage.payload as Pubkey
assertTrue(objectMessage.isSignatureValid(pubkey))
try {
address.pubkey = pubkey
} catch (e: Exception) {
@ -100,10 +100,10 @@ class BitmessageAddressTest : TestBase() {
@Test
fun `ensure V4Pubkey can be imported`() {
val address = BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h")
val `object` = TestUtils.loadObjectMessage(4, "V4Pubkey.payload")
`object`.decrypt(address.publicDecryptionKey)
val pubkey = `object`.payload as V4Pubkey
assertTrue(`object`.isSignatureValid(pubkey))
val objectMessage = TestUtils.loadObjectMessage(4, "V4Pubkey.payload")
objectMessage.decrypt(address.publicDecryptionKey)
val pubkey = objectMessage.payload as V4Pubkey
assertTrue(objectMessage.isSignatureValid(pubkey))
try {
address.pubkey = pubkey
} catch (e: Exception) {

View File

@ -170,12 +170,12 @@ class SerializationTest : TestBase() {
private fun doTest(resourceName: String, version: Int, expectedPayloadType: Class<*>) {
val data = TestUtils.getBytes(resourceName)
val `in` = ByteArrayInputStream(data)
val `object` = Factory.getObjectMessage(version, `in`, data.size)
val objectMessage = Factory.getObjectMessage(version, `in`, data.size)
val out = ByteArrayOutputStream()
assertNotNull(`object`)
`object`!!.write(out)
assertNotNull(objectMessage)
objectMessage!!.write(out)
assertArrayEquals(data, out.toByteArray())
assertEquals(expectedPayloadType.canonicalName, `object`.payload.javaClass.canonicalName)
assertEquals(expectedPayloadType.canonicalName, objectMessage.payload.javaClass.canonicalName)
}
@Test

View File

@ -42,12 +42,12 @@ class TestInventory : Inventory {
return ArrayList(inventory.values)
}
override fun storeObject(`object`: ObjectMessage) {
inventory.put(`object`.inventoryVector, `object`)
override fun storeObject(objectMessage: ObjectMessage) {
inventory.put(objectMessage.inventoryVector, objectMessage)
}
override fun contains(`object`: ObjectMessage): Boolean {
return inventory.containsKey(`object`.inventoryVector)
override fun contains(objectMessage: ObjectMessage): Boolean {
return inventory.containsKey(objectMessage.inventoryVector)
}
override fun cleanup() {

View File

@ -27,6 +27,6 @@ class CollectionsTest {
fun `ensure select random returns maximum possible items`() {
val list = LinkedList<Int>()
list += 0..9
assertEquals(9, Collections.selectRandom(9, list).size.toLong())
assertEquals(9, Collections.selectRandom(9, list).size)
}
}

View File

@ -16,7 +16,6 @@
package ch.dissem.bitmessage.utils
import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography
import ch.dissem.bitmessage.entity.BitmessageAddress
import ch.dissem.bitmessage.entity.Plaintext
import ch.dissem.bitmessage.entity.Plaintext.Type.MSG
@ -30,19 +29,13 @@ import org.junit.Assert.assertThat
import org.junit.Test
import java.util.*
class ConversationServiceTest {
class ConversationServiceTest : TestBase() {
private val alice = BitmessageAddress("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8")
private val bob = BitmessageAddress("BM-2cTtkBnb4BUYDndTKun6D9PjtueP2h1bQj")
private val messageRepository = mock<MessageRepository>()
private val conversationService = spy(ConversationService(messageRepository))
companion object {
init {
Singleton.initialize(BouncyCryptography())
}
}
@Test
fun `ensure conversation is sorted properly`() {
MockitoKotlin.registerInstanceCreator { UUID.randomUUID() }

View File

@ -111,11 +111,11 @@ class EncodeTest {
fun checkBytes(stream: ByteArrayOutputStream, vararg bytes: Int) {
assertEquals(bytes.size.toLong(), stream.size().toLong())
assertEquals(bytes.size, stream.size())
val streamBytes = stream.toByteArray()
for (i in bytes.indices) {
assertEquals(bytes[i].toByte().toLong(), streamBytes[i].toLong())
assertEquals(bytes[i].toByte(), streamBytes[i])
}
}
}

View File

@ -43,7 +43,7 @@ object TestUtils {
@JvmStatic fun int16(number: Int): ByteArray {
val out = ByteArrayOutputStream()
Encode.int16(number.toLong(), out)
Encode.int16(number, out)
return out.toByteArray()
}
@ -85,9 +85,9 @@ object TestUtils {
@Throws(DecryptionFailedException::class)
@JvmStatic fun loadContact(): BitmessageAddress {
val address = BitmessageAddress("BM-2cXxfcSetKnbHJX2Y85rSkaVpsdNUZ5q9h")
val `object` = TestUtils.loadObjectMessage(3, "V4Pubkey.payload")
`object`.decrypt(address.publicDecryptionKey)
address.pubkey = `object`.payload as V4Pubkey
val objectMessage = TestUtils.loadObjectMessage(3, "V4Pubkey.payload")
objectMessage.decrypt(address.publicDecryptionKey)
address.pubkey = objectMessage.payload as V4Pubkey
return address
}