Merge pull request #8842 from element-hq/feature/bca/send_to_dehydrated_devices
Fix | Share room keys with dehydrated devices
This commit is contained in:
commit
097d3923aa
|
@ -0,0 +1 @@
|
||||||
|
Element-Android session doesn't encrypt for a dehydrated device
|
|
@ -18,23 +18,10 @@ package org.matrix.android.sdk.internal.crypto.model
|
||||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
|
import org.matrix.android.sdk.api.session.crypto.crosssigning.CryptoCrossSigningKey
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeys
|
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeys
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeysWithUnsigned
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
||||||
|
|
||||||
internal object CryptoInfoMapper {
|
internal object CryptoInfoMapper {
|
||||||
|
|
||||||
fun map(deviceKeysWithUnsigned: DeviceKeysWithUnsigned): CryptoDeviceInfo {
|
|
||||||
return CryptoDeviceInfo(
|
|
||||||
deviceId = deviceKeysWithUnsigned.deviceId,
|
|
||||||
userId = deviceKeysWithUnsigned.userId,
|
|
||||||
algorithms = deviceKeysWithUnsigned.algorithms,
|
|
||||||
keys = deviceKeysWithUnsigned.keys,
|
|
||||||
signatures = deviceKeysWithUnsigned.signatures,
|
|
||||||
unsigned = deviceKeysWithUnsigned.unsigned,
|
|
||||||
trustLevel = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun map(cryptoDeviceInfo: CryptoDeviceInfo): DeviceKeys {
|
fun map(cryptoDeviceInfo: CryptoDeviceInfo): DeviceKeys {
|
||||||
return DeviceKeys(
|
return DeviceKeys(
|
||||||
deviceId = cryptoDeviceInfo.deviceId,
|
deviceId = cryptoDeviceInfo.deviceId,
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto.model.rest
|
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo
|
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
internal data class DeviceKeysWithUnsigned(
|
|
||||||
/**
|
|
||||||
* Required. The ID of the user the device belongs to. Must match the user ID used when logging in.
|
|
||||||
*/
|
|
||||||
@Json(name = "user_id")
|
|
||||||
val userId: String,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required. The ID of the device these keys belong to. Must match the device ID used when logging in.
|
|
||||||
*/
|
|
||||||
@Json(name = "device_id")
|
|
||||||
val deviceId: String,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required. The encryption algorithms supported by this device.
|
|
||||||
*/
|
|
||||||
@Json(name = "algorithms")
|
|
||||||
val algorithms: List<String>?,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required. Public identity keys. The names of the properties should be in the format <algorithm>:<device_id>.
|
|
||||||
* The keys themselves should be encoded as specified by the key algorithm.
|
|
||||||
*/
|
|
||||||
@Json(name = "keys")
|
|
||||||
val keys: Map<String, String>?,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required. Signatures for the device key object. A map from user ID, to a map from <algorithm>:<device_id> to the signature.
|
|
||||||
* The signature is calculated using the process described at https://matrix.org/docs/spec/appendices.html#signing-json.
|
|
||||||
*/
|
|
||||||
@Json(name = "signatures")
|
|
||||||
val signatures: Map<String, Map<String, String>>?,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional data added to the device key information by intermediate servers, and not covered by the signatures.
|
|
||||||
*/
|
|
||||||
@Json(name = "unsigned")
|
|
||||||
val unsigned: UnsignedDeviceInfo? = null
|
|
||||||
)
|
|
|
@ -34,7 +34,7 @@ internal data class KeysQueryResponse(
|
||||||
* For each device, the information returned will be the same as uploaded via /keys/upload, with the addition of an unsigned property.
|
* For each device, the information returned will be the same as uploaded via /keys/upload, with the addition of an unsigned property.
|
||||||
*/
|
*/
|
||||||
@Json(name = "device_keys")
|
@Json(name = "device_keys")
|
||||||
val deviceKeys: Map<String, Map<String, DeviceKeysWithUnsigned>>? = null,
|
val deviceKeys: Map<String, Map<String, Map<String, Any>>>? = null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If any remote homeservers could not be reached, they are recorded here. The names of the
|
* If any remote homeservers could not be reached, they are recorded here. The names of the
|
||||||
|
|
|
@ -22,7 +22,6 @@ import kotlinx.coroutines.joinAll
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import org.matrix.android.sdk.internal.crypto.api.CryptoApi
|
import org.matrix.android.sdk.internal.crypto.api.CryptoApi
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.DeviceKeysWithUnsigned
|
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryBody
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryBody
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
|
||||||
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
import org.matrix.android.sdk.internal.crypto.model.rest.RestKeyInfo
|
||||||
|
@ -52,7 +51,7 @@ internal class DefaultDownloadKeysForUsers @Inject constructor(
|
||||||
|
|
||||||
return if (bestChunkSize.shouldChunk()) {
|
return if (bestChunkSize.shouldChunk()) {
|
||||||
// Store server results in these mutable maps
|
// Store server results in these mutable maps
|
||||||
val deviceKeys = mutableMapOf<String, Map<String, DeviceKeysWithUnsigned>>()
|
val deviceKeys = mutableMapOf<String, Map<String, Map<String, Any>>>()
|
||||||
val failures = mutableMapOf<String, Map<String, Any>>()
|
val failures = mutableMapOf<String, Map<String, Any>>()
|
||||||
val masterKeys = mutableMapOf<String, RestKeyInfo?>()
|
val masterKeys = mutableMapOf<String, RestKeyInfo?>()
|
||||||
val selfSigningKeys = mutableMapOf<String, RestKeyInfo?>()
|
val selfSigningKeys = mutableMapOf<String, RestKeyInfo?>()
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
|
import org.amshove.kluent.internal.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.matrix.android.sdk.internal.crypto.model.rest.KeysQueryResponse
|
||||||
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
|
||||||
|
class KeysQueryResponseTest {
|
||||||
|
|
||||||
|
private val moshi = MoshiProvider.providesMoshi()
|
||||||
|
private val keysQueryResponseAdapter = moshi.adapter(KeysQueryResponse::class.java)
|
||||||
|
|
||||||
|
private fun aKwysQueryResponseWithDehydrated(): KeysQueryResponse {
|
||||||
|
val rawResponseWithDehydratedDevice = """
|
||||||
|
{
|
||||||
|
"device_keys": {
|
||||||
|
"@dehydration2:localhost": {
|
||||||
|
"TDHZGMDVNO": {
|
||||||
|
"algorithms": [
|
||||||
|
"m.olm.v1.curve25519-aes-sha2",
|
||||||
|
"m.megolm.v1.aes-sha2"
|
||||||
|
],
|
||||||
|
"device_id": "TDHZGMDVNO",
|
||||||
|
"keys": {
|
||||||
|
"curve25519:TDHZGMDVNO": "ClMOrHlQJqaqr4oESYyPURwD4BSQxMlEZZk/AnYxVSk",
|
||||||
|
"ed25519:TDHZGMDVNO": "5iZ4zfk0URyIH8YOIWnXmJo41Vn34IixGYphkMdDzik"
|
||||||
|
},
|
||||||
|
"signatures": {
|
||||||
|
"@dehydration2:localhost": {
|
||||||
|
"ed25519:TDHZGMDVNO": "O6VP+ELiCVAJGHaRdReKga0LGMQahjRnp4znZH7iJO6maZV8aSXnpugSoVsSPRvQ4GBkjX+KXAXU+ODZ0J8MDg",
|
||||||
|
"ed25519:YZ0EmlbDX+t/m/MB5EWkQLw8cEDg7hX4Zy9699h3hd8": "lG3idYliFGOAe4F/7tENIQ6qI0d41VQKY34BHyVvvWKbv63zDDO5kBTwBeXfUSEeRqyxET3SXLXfB1D8E8LUDg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_id": "@dehydration2:localhost",
|
||||||
|
"unsigned": {
|
||||||
|
"device_display_name": "localhost:8080: Chrome on macOS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ": {
|
||||||
|
"algorithms": [
|
||||||
|
"m.olm.v1.curve25519-aes-sha2",
|
||||||
|
"m.megolm.v1.aes-sha2"
|
||||||
|
],
|
||||||
|
"dehydrated": true,
|
||||||
|
"device_id": "Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ",
|
||||||
|
"keys": {
|
||||||
|
"curve25519:Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ": "Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ",
|
||||||
|
"ed25519:Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ": "sVY5Xq13sIdhC4We/p5CH69++GsIWRNUhHijtucBirs"
|
||||||
|
},
|
||||||
|
"signatures": {
|
||||||
|
"@dehydration2:localhost": {
|
||||||
|
"ed25519:Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ": "e2aVrdnD/kor2T0Ok/4SC32MW4WB5JXFSd2wnXV8apxFJBfbdZErANiUbo1Zz/HAasaXM5NBfkr/9gVTdph9BQ",
|
||||||
|
"ed25519:YZ0EmlbDX+t/m/MB5EWkQLw8cEDg7hX4Zy9699h3hd8": "rVzeE1LbB12XOlckxjRLjt3eq2jVlek6OJ4p08+8g8CMoiJDcw1OVzbJuG/8u6ryarxQF6Yqr4Xu2TqCPBmHDw"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_id": "@dehydration2:localhost",
|
||||||
|
"unsigned": {
|
||||||
|
"device_display_name": "Dehydrated device"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
return keysQueryResponseAdapter.fromJson(rawResponseWithDehydratedDevice)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Should parse correctly devices with new dehydrated field`() {
|
||||||
|
val aKeysQueryResponse = aKwysQueryResponseWithDehydrated()
|
||||||
|
|
||||||
|
val pojoToJson = keysQueryResponseAdapter.toJson(aKeysQueryResponse)
|
||||||
|
|
||||||
|
val rawAdapter = moshi.adapter(Map::class.java)
|
||||||
|
|
||||||
|
val rawJson = rawAdapter.fromJson(pojoToJson)!!
|
||||||
|
|
||||||
|
val deviceKeys = (rawJson["device_keys"] as Map<*, *>)["@dehydration2:localhost"] as Map<*, *>
|
||||||
|
|
||||||
|
assertEquals(deviceKeys.keys.size, 2)
|
||||||
|
|
||||||
|
val dehydratedDevice = deviceKeys["Y2gISVBZ024gKKAe6Xos44cDbNlO/49YjaOyiqFwjyQ"] as Map<*, *>
|
||||||
|
|
||||||
|
assertEquals(dehydratedDevice["dehydrated"] as? Boolean, true)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue