Allow missing recipient for drafts

This commit is contained in:
Christian Basler 2018-02-16 17:04:24 +01:00
parent fab1c06135
commit 681ea148db
2 changed files with 59 additions and 18 deletions

View File

@ -87,10 +87,10 @@ class Plaintext private constructor(
if (to == null) { if (to == null) {
return return
} }
if (this.to != null) { this.to?.let {
if (this.to!!.version != 0L) if (it.version != 0L)
throw IllegalStateException("Correct address already set") throw IllegalStateException("Correct address already set")
if (!Arrays.equals(this.to!!.ripe, to.ripe)) { if (!Arrays.equals(it.ripe, to.ripe)) {
throw IllegalArgumentException("RIPEs don't match") throw IllegalArgumentException("RIPEs don't match")
} }
} }
@ -187,7 +187,8 @@ class Plaintext private constructor(
Factory.getObjectMessage( Factory.getObjectMessage(
3, 3,
ByteArrayInputStream(ackMessage), ByteArrayInputStream(ackMessage),
ackMessage.size) ackMessage.size
)
} else null } else null
}, },
conversationId = conversationId, conversationId = conversationId,
@ -243,7 +244,8 @@ class Plaintext private constructor(
Factory.getObjectMessage( Factory.getObjectMessage(
3, 3,
ByteArrayInputStream(ackMsg), ByteArrayInputStream(ackMsg),
ackMsg.size) ackMsg.size
)
} else { } else {
Factory.createAck(builder.from!!, builder.ackData, builder.ttl) Factory.createAck(builder.from!!, builder.ackData, builder.ttl)
} }
@ -462,7 +464,12 @@ class Plaintext private constructor(
} }
}.invoke() }.invoke()
if (item.type == MSG) { if (item.type == MSG) {
out.write(item.to?.ripe ?: throw IllegalStateException("No recipient set for message")) // A draft without recipient is allowed, therefore this workaround.
item.to?.let { out.write(it.ripe) } ?: if (item.status == Status.DRAFT) {
out.write(ByteArray(20))
} else {
throw IllegalStateException("No recipient set for message")
}
} }
Encode.varInt(item.encodingCode, out) Encode.varInt(item.encodingCode, out)
Encode.varInt(item.message.size, out) Encode.varInt(item.message.size, out)
@ -508,7 +515,12 @@ class Plaintext private constructor(
} }
} }
if (item.type == MSG) { if (item.type == MSG) {
buffer.put(item.to!!.ripe) // A draft without recipient is allowed, therefore this workaround.
item.to?.let { buffer.put(it.ripe) } ?: if (item.status == Status.DRAFT) {
buffer.put(ByteArray(20))
} else {
throw IllegalStateException("No recipient set for message")
}
} }
Encode.varInt(item.encodingCode, buffer) Encode.varInt(item.encodingCode, buffer)
Encode.varBytes(item.message, buffer) Encode.varBytes(item.message, buffer)
@ -727,15 +739,17 @@ class Plaintext private constructor(
internal fun prepare(): Builder { internal fun prepare(): Builder {
if (from == null) { if (from == null) {
from = BitmessageAddress(Factory.createPubkey( from = BitmessageAddress(
addressVersion, Factory.createPubkey(
stream, addressVersion,
publicSigningKey!!, stream,
publicEncryptionKey!!, publicSigningKey!!,
nonceTrialsPerByte, publicEncryptionKey!!,
extraBytes, nonceTrialsPerByte,
behaviorBitfield extraBytes,
)) behaviorBitfield
)
)
} }
if (to == null && type != Type.BROADCAST && destinationRipe != null) { if (to == null && type != Type.BROADCAST && destinationRipe != null) {
to = BitmessageAddress(0, 0, destinationRipe!!) to = BitmessageAddress(0, 0, destinationRipe!!)
@ -743,7 +757,7 @@ class Plaintext private constructor(
if (preventAck) { if (preventAck) {
ackData = null ackData = null
ackMessage = null ackMessage = null
} else if (type == MSG && ackMessage == null && ackData == null) { } else if (type == MSG && ackMessage == null && ackData == null && to?.has(Feature.DOES_ACK) == true) {
ackData = cryptography().randomBytes(Msg.ACK_LENGTH) ackData = cryptography().randomBytes(Msg.ACK_LENGTH)
} }
if (ttl <= 0) { if (ttl <= 0) {
@ -784,7 +798,9 @@ class Plaintext private constructor(
.publicEncryptionKey(Decode.bytes(input, 64)) .publicEncryptionKey(Decode.bytes(input, 64))
.nonceTrialsPerByte(if (version >= 3) Decode.varInt(input) else 0) .nonceTrialsPerByte(if (version >= 3) Decode.varInt(input) else 0)
.extraBytes(if (version >= 3) Decode.varInt(input) else 0) .extraBytes(if (version >= 3) Decode.varInt(input) else 0)
.destinationRipe(if (type == MSG) Decode.bytes(input, 20) else null) .destinationRipe(if (type == MSG) Decode.bytes(input, 20).let {
if (it.any { x -> x != 0.toByte() }) it else null
} else null)
.encoding(Decode.varInt(input)) .encoding(Decode.varInt(input))
.message(Decode.varBytes(input)) .message(Decode.varBytes(input))
.ackMessage(if (type == MSG) Decode.varBytes(input) else null) .ackMessage(if (type == MSG) Decode.varBytes(input) else null)

View File

@ -123,6 +123,31 @@ class SerializationTest : TestBase() {
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@Test
fun `ensure plaintext without recipient can be serialized (needed for saving drafts)`() {
val expected = Plaintext.Builder(MSG)
.from(TestUtils.loadIdentity("BM-2cSqjfJ8xK6UUn5Rw3RpdGQ9RsDkBhWnS8"))
.message(Message.Builder()
.subject("Subject")
.body("Message")
.build())
.signature(ByteArray(0))
.status(Plaintext.Status.DRAFT)
.build()
val out = ByteArrayOutputStream()
expected.writer().write(out)
val input = ByteArrayInputStream(out.toByteArray())
val actual = Plaintext.read(MSG, input)
actual.status = Plaintext.Status.DRAFT // status isn't serialized, that's OK
// Received is automatically set on deserialization, so we'll need to set it to null
val received = Plaintext::class.java.getDeclaredField("received")
received.isAccessible = true
received.set(actual, null)
assertEquals(expected, actual)
}
@Test @Test
fun `ensure plaintext with ack message is serialized and deserialized correctly`() { fun `ensure plaintext with ack message is serialized and deserialized correctly`() {
val expected = Plaintext.Builder(MSG) val expected = Plaintext.Builder(MSG)