Move method to JsonCanonicalizer and fix test compilation

This commit is contained in:
Benoit Marty 2019-07-09 17:31:44 +02:00
parent c19b1f917f
commit e9700e04d8
12 changed files with 53 additions and 64 deletions

View File

@ -59,7 +59,7 @@ internal class ChunkEntityTest : InstrumentedTest {
val chunk: ChunkEntity = realm.createObject() val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent() val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.events.size shouldEqual 1 chunk.timelineEvents.size shouldEqual 1
} }
} }


@ -70,7 +70,7 @@ internal class ChunkEntityTest : InstrumentedTest {
val fakeEvent = createFakeMessageEvent() val fakeEvent = createFakeMessageEvent()
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS) chunk.add("roomId", fakeEvent, PaginationDirection.FORWARDS)
chunk.events.size shouldEqual 1 chunk.timelineEvents.size shouldEqual 1
} }
} }


@ -126,7 +126,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll("roomId", createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS) chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.events.size shouldEqual 60 chunk1.timelineEvents.size shouldEqual 60
} }
} }


@ -142,7 +142,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS) chunk1.addAll("roomId", eventsForChunk1, PaginationDirection.FORWARDS)
chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS) chunk2.addAll("roomId", eventsForChunk2, PaginationDirection.BACKWARDS)
chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS) chunk1.merge("roomId", chunk2, PaginationDirection.BACKWARDS)
chunk1.events.size shouldEqual 40 chunk1.timelineEvents.size shouldEqual 40
chunk1.isLastForward.shouldBeTrue() chunk1.isLastForward.shouldBeTrue()
} }
} }

View File

@ -48,7 +48,6 @@ import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAct
import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting import im.vector.matrix.android.internal.crypto.algorithms.IMXEncrypting
import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory import im.vector.matrix.android.internal.crypto.algorithms.megolm.MXMegolmEncryptionFactory
import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmEncryptionFactory
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
@ -74,12 +73,12 @@ import im.vector.matrix.android.internal.session.room.membership.RoomMembers
import im.vector.matrix.android.internal.session.sync.model.SyncResponse import im.vector.matrix.android.internal.session.sync.model.SyncResponse
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import im.vector.matrix.android.internal.util.fetchCopied import im.vector.matrix.android.internal.util.fetchCopied
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.matrix.olm.OlmManager import org.matrix.olm.OlmManager
import timber.log.Timber import timber.log.Timber
import java.io.File
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject import javax.inject.Inject
@ -766,7 +765,7 @@ internal class CryptoManager @Inject constructor(
private suspend fun uploadDeviceKeys(): Try<KeysUploadResponse> { private suspend fun uploadDeviceKeys(): Try<KeysUploadResponse> {
// Prepare the device keys data to send // Prepare the device keys data to send
// Sign it // Sign it
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, getMyDevice().signalableJSONDictionary())
getMyDevice().signatures = objectSigner.signObject(canonicalJson) getMyDevice().signatures = objectSigner.signObject(canonicalJson)


// For now, we set the device id explicitly, as we may not be using the // For now, we set the device id explicitly, as we may not be using the

View File

@ -28,6 +28,7 @@ import im.vector.matrix.android.internal.crypto.model.OlmSessionWrapper
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.convertFromUTF8 import im.vector.matrix.android.internal.util.convertFromUTF8
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import org.matrix.olm.* import org.matrix.olm.*
@ -728,7 +729,7 @@ internal class MXOlmDevice @Inject constructor(
@Throws(Exception::class) @Throws(Exception::class)
fun verifySignature(key: String, jsonDictionary: Map<String, Any>, signature: String) { fun verifySignature(key: String, jsonDictionary: Map<String, Any>, signature: String) {
// Check signature on the canonical version of the JSON // Check signature on the canonical version of the JSON
olmUtility!!.verifyEd25519Signature(signature, key, MoshiProvider.getCanonicalJson<Map<*, *>>(Map::class.java, jsonDictionary)) olmUtility!!.verifyEd25519Signature(signature, key, JsonCanonicalizer.getCanonicalJson(Map::class.java, jsonDictionary))
} }


/** /**

View File

@ -22,8 +22,8 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.crypto.model.MXKey import im.vector.matrix.android.internal.crypto.model.MXKey
import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse import im.vector.matrix.android.internal.crypto.model.rest.KeysUploadResponse
import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask import im.vector.matrix.android.internal.crypto.tasks.UploadKeysTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import org.matrix.olm.OlmAccount import org.matrix.olm.OlmAccount
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -158,7 +158,7 @@ internal class OneTimeKeysUploader @Inject constructor(
k["key"] = curve25519Map.getValue(key_id) k["key"] = curve25519Map.getValue(key_id)


// the key is also signed // the key is also signed
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, k) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, k)


k["signatures"] = objectSigner.signObject(canonicalJson) k["signatures"] = objectSigner.signObject(canonicalJson)



View File

@ -22,8 +22,7 @@ import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_OLM
import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.MXOlmDevice
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedMessage import im.vector.matrix.android.internal.crypto.model.rest.EncryptedMessage
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -81,7 +80,7 @@ internal class MessageEncrypter @Inject constructor(private val credentials: Cre
recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!! recipientsKeysMap["ed25519"] = deviceInfo.fingerprint()!!
payloadJson["recipient_keys"] = recipientsKeysMap payloadJson["recipient_keys"] = recipientsKeysMap


val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson)) val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!! ciphertext[deviceKey] = olmDevice.encryptMessage(deviceKey, sessionId!!, payloadString!!)!!
} }
} }

View File

@ -36,7 +36,7 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository import im.vector.matrix.android.internal.crypto.repository.WarnOnUnknownDeviceRepository
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.convertToUTF8 import im.vector.matrix.android.internal.util.convertToUTF8
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -263,7 +263,7 @@ internal class MXMegolmEncryption(


// Get canonical Json from // Get canonical Json from


val payloadString = convertToUTF8(MoshiProvider.getCanonicalJson(Map::class.java, payloadJson)) val payloadString = convertToUTF8(JsonCanonicalizer.getCanonicalJson(Map::class.java, payloadJson))
val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString!!) val ciphertext = olmDevice.encryptGroupMessage(session.sessionId, payloadString!!)


val map = HashMap<String, Any>() val map = HashMap<String, Any>()

View File

@ -55,6 +55,7 @@ import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -176,7 +177,7 @@ internal class KeysBackup @Inject constructor(
megolmBackupAuthData.publicKey = publicKey megolmBackupAuthData.publicKey = publicKey
} }


val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())


megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson) megolmBackupAuthData.signatures = objectSigner.signObject(canonicalJson)


@ -456,7 +457,7 @@ internal class KeysBackup @Inject constructor(


if (trust) { if (trust) {
// Add current device signature // Add current device signature
val canonicalJson = MoshiProvider.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary()) val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, authData.signalableJSONDictionary())


val deviceSignatures = objectSigner.signObject(canonicalJson) val deviceSignatures = objectSigner.signObject(canonicalJson)



View File

@ -29,8 +29,8 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import timber.log.Timber import timber.log.Timber


internal class IncomingSASVerificationTransaction( internal class IncomingSASVerificationTransaction(
@ -147,7 +147,7 @@ internal class IncomingSASVerificationTransaction(


//The hash commitment is the hash (using the selected hash algorithm) of the unpadded base64 representation of QB, //The hash commitment is the hash (using the selected hash algorithm) of the unpadded base64 representation of QB,
// concatenated with the canonical JSON representation of the content of the m.key.verification.start message // concatenated with the canonical JSON representation of the content of the m.key.verification.start message
val concat = getSAS().publicKey + MoshiProvider.getCanonicalJson(KeyVerificationStart::class.java, startReq!!) val concat = getSAS().publicKey + JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, startReq!!)
accept.commitment = hashUsingAgreedHashMethod(concat) ?: "" accept.commitment = hashUsingAgreedHashMethod(concat) ?: ""
//we need to send this to other device now //we need to send this to other device now
state = SasVerificationTxState.SendingAccept state = SasVerificationTxState.SendingAccept

View File

@ -27,8 +27,8 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationMac
import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.JsonCanonicalizer
import timber.log.Timber import timber.log.Timber


internal class OutgoingSASVerificationRequest( internal class OutgoingSASVerificationRequest(
@ -164,7 +164,7 @@ internal class OutgoingSASVerificationRequest(
// in Bobs m.key.verification.key and the content of Alices m.key.verification.start message. // in Bobs m.key.verification.key and the content of Alices m.key.verification.start message.


//check commitment //check commitment
val concat = vKey.key + MoshiProvider.getCanonicalJson(KeyVerificationStart::class.java, startReq!!) val concat = vKey.key + JsonCanonicalizer.getCanonicalJson(KeyVerificationStart::class.java, startReq!!)
val otherCommitment = hashUsingAgreedHashMethod(concat) ?: "" val otherCommitment = hashUsingAgreedHashMethod(concat) ?: ""


if (accepted!!.commitment.equals(otherCommitment)) { if (accepted!!.commitment.equals(otherCommitment)) {

View File

@ -16,6 +16,7 @@


package im.vector.matrix.android.internal.database.helper package im.vector.matrix.android.internal.database.helper


import androidx.annotation.VisibleForTesting
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.send.SendState
@ -102,11 +103,12 @@ internal fun ChunkEntity.updateSenderDataFor(eventIds: List<String>) {
} }
} }


private fun ChunkEntity.add(roomId: String, @VisibleForTesting
event: Event, internal fun ChunkEntity.add(roomId: String,
direction: PaginationDirection, event: Event,
stateIndexOffset: Int = 0, direction: PaginationDirection,
isUnlinked: Boolean = false) { stateIndexOffset: Int = 0,
isUnlinked: Boolean = false) {


assertIsManaged() assertIsManaged()
if (event.eventId != null && timelineEvents.find(event.eventId) != null) { if (event.eventId != null && timelineEvents.find(event.eventId) != null) {
@ -149,14 +151,14 @@ private fun ChunkEntity.add(roomId: String,


internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
return when (direction) { return when (direction) {
PaginationDirection.FORWARDS -> forwardsDisplayIndex PaginationDirection.FORWARDS -> forwardsDisplayIndex
PaginationDirection.BACKWARDS -> backwardsDisplayIndex PaginationDirection.BACKWARDS -> backwardsDisplayIndex
} ?: defaultValue } ?: defaultValue
} }


internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
return when (direction) { return when (direction) {
PaginationDirection.FORWARDS -> forwardsStateIndex PaginationDirection.FORWARDS -> forwardsStateIndex
PaginationDirection.BACKWARDS -> backwardsStateIndex PaginationDirection.BACKWARDS -> backwardsStateIndex
} ?: defaultValue } ?: defaultValue
} }

View File

@ -23,7 +23,6 @@ import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
import im.vector.matrix.android.internal.session.sync.model.UserAccountData import im.vector.matrix.android.internal.session.sync.model.UserAccountData
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback
import im.vector.matrix.android.internal.util.JsonCanonicalizer




object MoshiProvider { object MoshiProvider {
@ -50,19 +49,6 @@ object MoshiProvider {
return moshi return moshi
} }


// TODO Move
fun <T> getCanonicalJson(type: Class<T>, o: T): String {
val adapter = moshi.adapter<T>(type)

val json = adapter.toJson(o)

// Canonicalize manually
val can = JsonCanonicalizer.canonicalize(json)

val jsonSafe = can.replace("\\/", "/")

return jsonSafe
}
} }





View File

@ -16,6 +16,8 @@


package im.vector.matrix.android.internal.util package im.vector.matrix.android.internal.util


import androidx.annotation.VisibleForTesting
import im.vector.matrix.android.internal.di.MoshiProvider
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
@ -28,22 +30,24 @@ import java.util.*
*/ */
object JsonCanonicalizer { object JsonCanonicalizer {


fun canonicalize(json: String): String { fun <T> getCanonicalJson(type: Class<T>, o: T): String {
var can: String? = null val adapter = MoshiProvider.providesMoshi().adapter<T>(type)
try {
val _json = JSONObject(json)


can = _canonicalize(_json) // Canonicalize manually
return canonicalize(adapter.toJson(o))
.replace("\\/", "/")
}

@VisibleForTesting
fun canonicalize(jsonString: String): String {
return try {
val jsonObject = JSONObject(jsonString)

canonicalizeRecursive(jsonObject)
} catch (e: JSONException) { } catch (e: JSONException) {
Timber.e(e, "Unable to canonicalize") Timber.e(e, "Unable to canonicalize")
jsonString
} }

if (can == null) {
Timber.e("Error")
return json
}

return can
} }


/** /**
@ -52,11 +56,8 @@ object JsonCanonicalizer {
* @param src the src * @param src the src
* @return the canonicalize element * @return the canonicalize element
*/ */
private fun _canonicalize(src: Any?): String? { private fun canonicalizeRecursive(src: Any): String {
// sanity check // sanity check
if (null == src) {
return null
}


when (src) { when (src) {
is JSONArray -> { is JSONArray -> {
@ -65,7 +66,7 @@ object JsonCanonicalizer {
val result = StringBuilder("[") val result = StringBuilder("[")


for (i in 0 until srcArray!!.length()) { for (i in 0 until srcArray!!.length()) {
result.append(_canonicalize(srcArray.get(i))) result.append(canonicalizeRecursive(srcArray.get(i)))
if (i < srcArray.length() - 1) { if (i < srcArray.length() - 1) {
result.append(",") result.append(",")
} }
@ -89,7 +90,7 @@ object JsonCanonicalizer {
.append(attribute.value) .append(attribute.value)
.append("\"") .append("\"")
.append(":") .append(":")
.append(_canonicalize(src[attribute.value])) .append(canonicalizeRecursive(src[attribute.value]))


if (attribute.index < attributes.size - 1) { if (attribute.index < attributes.size - 1) {
result.append(",") result.append(",")